Недавно я рассмотрел странное поведение метода синхронного приема .Net.Мне нужно было написать приложение, в котором есть узлы, которые общаются друг с другом, отправляя / получая данные.Каждый сервер имеет цикл приема, который является синхронным, после получения сериализованного класса он десериализуется и обрабатывает его.После этого он отправляет этот сериализованный класс асинхронно некоторым выбранным узлам (используя AsynchSendTo).
MSDN четко говорит, что:
"Если вы используете Socket-ориентированный сокет,Метод Receive будет считывать столько данных, сколько доступно, вплоть до размера буфера.Если удаленный хост завершает соединение Socket с помощью метода Shutdown и все доступные данные были получены, метод 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;
}
Мой вопрос: неправильно ли я использую синхронный прием?Почему он не блокирует событие, хотя есть данные для получения?