C# · 12月 26, 2021

.NET C#同步接收不会阻止

最近我解决了.Net同步接收方法的奇怪行为.我需要编写一个具有通过发送/接收数据相互通信的节点的应用程序.每个服务器都有一个同步的接收循环,在接收到序列化类后,它会反序列化并处理它.之后,它将这个序列化类异步发送到一些选定的节点(使用AsynchSendTo).

MSDN清楚地说:

“If you are using a connection-oriented Socket,the Receive method
will read as much data as is available,up to the size of the buffer.
If the remote host shuts down the Socket connection with the Shutdown
method,and all available data has been received,the Receive method
will complete immediately and return zero bytes.”

在我的情况下,这不是真的.在接收没有阻塞并且在建立连接之后立即返回0字节(非确定性的位置)时,存在一些随机情况.我百分百肯定发件人发送的是至少1000字节.另一个有趣的事实是:在接收睡眠之前(500)一切正常.以下是接收代码:

_listener = new Socket(AddressFamily.InterNetwork,SocketType.Stream,ProtocolType.Tcp);try{ _listener.Bind(_serverEndpoint); _listener.Listen(Int32.MaxValue); while (true) { Console.WriteLine(“Waiting for connection…”); Socket handler = _listener.Accept(); int totalBytes = 0; int bytesRec; var bytes = new byte[DATAGRAM_BUFFER]; do { //Thread.Sleep(500); bytesRec = handler.Receive(bytes,totalBytes,handler.Available,SocketFlags.None); totalBytes += bytesRec; } while (bytesRec > 0); handler.Shutdown(SocketShutdown.Both); handler.Close(); }}catch (SocketException e){ Console.WriteLine(e);}

发送部分:

public void AsynchSendTo(Datagram datagram,IPEndPoint recipient){ byte[] byteDatagram = SerializeDatagram(datagram); try { var socket = new Socket(AddressFamily.InterNetwork,ProtocolType.Tcp); socket.BeginConnect(recipient,ConnectCallback,new StateObject(byteDatagram,byteDatagram.Length,socket)); } catch (SocketException e) { Console.WriteLine(e); }}public void ConnectCallback(IAsyncResult result){ try { var stateObject = (StateObject)result.AsyncState; var socket = stateObject.socket; socket.EndConnect(result); socket.BeginSend(stateObject.Data,stateObject.Data.Length,new AsyncCallback(SendCallback),socket); } catch (Exception ex) { Console.WriteLine(“catched!” + ex.ToString()); }}public void SendCallback(IAsyncResult result){ try { var client = (Socket)result.AsyncState; client.EndSend(result); client.Shutdown(SocketShutdown.Both); client.Close(); } catch (Exception ex) { Console.WriteLine(ex); }}class StateObject{ public Byte[] Data { get; set; } public int Size; public Socket Socket;}

我的问题:我是否以错误的方式使用同步接收?尽管有数据要接收,为什么它不会阻止事件?

解决方法 你在脚下射击自己. bytesRec = handler.Receive(bytes,SocketFlags.None);

在连接的最开始,Available将为0,强制它立即返回0.相反,您应该指定缓冲区中可用的字节数(例如bytes.Length-totalBytes),然后它也将阻塞.