简体   繁体   English

使用Bouncy Castle和Xamarin和Java Server无法读取流(IOException:非阻塞套接字会阻塞)

[英]Cannot read from stream (IOException: non-blocking socket would block) using Bouncy Castle with Xamarin and Java Server

Prerequisites: I'm using Xamarin to write a mobile app which should exchange small message chunks with a java server. 先决条件:我正在使用Xamarin编写一个移动应用程序,该应用程序应与Java服务器交换小消息块。 I'm using the .NET implementation of Bouncy Castle for sending data over TLS, since I'm restricted to a specific cipher suite (TLS_ECDH_anon_WITH_AES_256_CBC_SHA) which is not supported by default for Android phones above API Level 23. 我使用Bouncy Castle的.NET实现通过TLS发送数据,因为我仅限于特定的密码套件(TLS_ECDH_anon_WITH_AES_256_CBC_SHA),默认情况下,API级别23以上的Android手机不支持该密码套件。

The problem: If I only try to send data via the following code, everything is fine. 问题:如果我仅尝试通过以下代码发送数据,一切都很好。 But if I try to also read the response back, the stream hangs for some seconds and then throws the exception System.IO.IOException: Unable to read data from the transport connection: Operation on non-blocking socket would block. 但是,如果我尝试也读回响应,则流挂起几秒钟,然后引发异常System.IO.IOException: Unable to read data from the transport connection: Operation on non-blocking socket would block. However, as you can see in the example below, I'm initializing Bouncy Castle's TlsClientProtocol with the "blocking"-constructor (docu says it is blocking if a stream is given), so the socket should not be non-blocking. 但是,正如您在下面的示例中看到的那样,我正在使用“阻塞”构造函数初始化Bouncy Castle的TlsClientProtocol(docu表示如果提供了流,它将阻塞),因此套接字不应是非阻塞的。

Furthermore, the server receives the data almost instantly, but only if no reading from the client will follow in code. 此外,服务器几乎立即接收数据,但前提是没有来自客户端的读取将跟随代码。 If a .Read(..) or .DataAvailable check comes afterwards, the server receives the data after the exception occurred or it does not receive anything. 如果之后出现.DataAvailable .Read(..).DataAvailable检查,则服务器将在发生异常后接收数据,或者不接收任何数据。

Purged/simplified code version: 清除/简化的代码版本:

Clientside Xamarin app: 客户端Xamarin应用:

TcpClient client = new TcpClient() { ReceiveTimeout = 5000, SendTimeout = 5000 };
client.Connect(ip, port);
NetworkStream stream = client.GetStream();

TlsClientProtocol protocol =
    new TlsClientProtocol(stream, new Org.BouncyCastle.Security.SecureRandom());
protocol.Connect(new CustomTlsClient()); // CustomTlsClient derives from DefaultTlsClient and is used to overwrite the CipherSuite
protocol.Stream.Write(data, 0, data.length);
protocol.Stream.Flush();
// Sending won't work too if the following line is present
protocol.Stream.Read(buffer, 0, buffer.Length);

Server side java application (I have no access to it, but i got the info that it is implemented that way): 服务器端Java应用程序(我无权访问它,但是我得到了以这种方式实现的信息):

SSLServerSocket socket = (SSLServerSocket)SSLServerSocketFactory.getDefault().createServerSocket(port);
String[] enabledCipherSuites = new String[] { "TLS_ECDH_anon_WITH_AES_256_CBC_SHA" };
socket.setEnabledCipherSuites(enabledCipherSuites);

SSLSocket clientSocket = socket.accept();
clientSocket.startHandshake();
BufferedReader in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
PrintWriter out = new PrintWriter(clientSocket.getOutputStream(), true);

String request = in.readLine(); // Works only if the client won't read afterwards
out.println(request);

Some of the failed solution attempts so far: 到目前为止,一些失败的解决方案尝试:

  • Manually set client.Client.Blocking = false -- nothing changed 手动设置client.Client.Blocking = false-不变
  • The exception says the socket is non-blocking, therefore I tried to wait in a loop via protocol.Stream.DataAvailable -- It was waiting forever, but after I quit the app, the server received the message (during the loop nothing was received by the server) 异常表示套接字未阻塞,因此我尝试通过protocol.Stream.DataAvailable在循环中等待-它一直在等待,但是退出应用程序后,服务器收到了消息(在循环过程中未收到任何消息由服务器)
  • I wrote my own java server to test this behaviour on a localhost -- same results 我编写了自己的Java服务器以在本地主机上测试此行为-相同的结果
  • I tried to use BeginSend / BeginRead -- same results 我尝试使用BeginSend / BeginRead-相同的结果

So, I'm actually starting to tear my hairs out of my head. 因此,我实际上开始从头上拔掉头发。 Any help is appreciated! 任何帮助表示赞赏!

EDIT: I fortunately found the solution, it was just a dumb error I made, see my answer below. 编辑:幸运的是,我找到了解决方案,这只是我犯的一个愚蠢的错误,请参阅下面的答案。

It turned out, that the exception message was somehow misleading. 原来,异常消息在某种程度上具有误导性。 The socket was in blocking mode and the mistake was ... how should I call it ... dumb. 套接字处于阻止模式,错误是……我该怎么称呼……愚蠢。 I simply forgot to append a newline (\\n). 我只是忘了添加一个换行符(\\ n)。 This was also the reason why the java server did not receive anything until the TcpClient was disposed - it was waiting for the newline. 这也是Java服务器直到TcpClient被处理之前一直没有收到任何消息的原因-它正在等待换行符。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM