最近我遇到了一个奇怪的.Net同步接收方法的行为。我需要编写一个应用程序,其中节点通过发送/接收数据进行通信。每个服务器都有一个接收循环,该循环是同步的,在接收序列化类之后,它会对其进行反序列化和处理。之后,它使用AsynchSendTo异步地将此序列化类发送到一些选择的节点。
MSDN明确指出:
"如果您正在使用面向连接的Socket,则Receive方法将读取尽可能多的可用数据,直到缓冲区的大小为止。如果远程主机使用Shutdown方法关闭Socket连接,并且已接收到所有可用数据,则Receive方法将立即完成并返回零字节。"
在我的情况下,这不是真的。有一些随机情况,当建立连接后,Receive不会阻塞并立即返回0字节(非确定性情况)。我100%确定发送方至少发送了1000字节。还有一个有趣的事实:在接收之前加入Sleep(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, SocketType.Stream, 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, 0, stateObject.Data.Length, 0, 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;
}
我的问题是:我是否错误地使用了同步接收?为什么它没有阻塞,即使有数据可以接收?