Recientemente he abordado un comportamiento extraño del método .Net synchronous receive. Necesitaba escribir una aplicación que tiene nodos que se comunican entre sí enviando/recibiendo datos. Cada servidor tiene un bucle de recibo que es sincrónico, después de recibir una clase serializada, lo deserializa y lo procesa. Después de eso envía asincrónicamente esta clase serializada a algunos nodos elegidos (usando AsynchSendTo)..NET C# La recepción sincrónica no bloquea
El MSDN dice claramente que:
"Si está utilizando un conector orientado a conexión, el método Recibe va a leer todos los datos que está disponible, hasta el tamaño de la memoria intermedia Si. el host remoto apaga la conexión de Socket con el método Shutdown , y se han recibido todos los datos disponibles, el método Receive se completará inmediatamente y devolverá cero bytes ".
En mi caso, no es cierto. Hay algunos casos aleatorios cuando Receive no bloquea y devuelve 0 bytes (situtation no determinista) inmediatamente después de establecer la conexión. Estoy 100% seguro de que el remitente estaba enviando por lo menos 1000 bytes. Un hecho más curioso: al poner Sleep (500) antes de recibir todo funciona bien. A continuación se presenta el código de recepción:
_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);
}
también la parte que envía:
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;
}
Mi pregunta: estoy usando el sincrónica reciben de una manera incorrecta? ¿Por qué no bloquea el evento aunque haya datos para recibir?
Dado que su pregunta no es específicamente sobre el problema que está teniendo, se resuelve con un descanso antes de la lectura. Desde medio segundo cada bucle puede realmente pasar factura con latencia si se lee mucho de una vez, ¿ha intentado dormir después de la lectura con un tiempo de espera más pequeño, como 100 mseg? Esto me ha funcionado al leer los puertos seriales, pero también fue cuando también se produjo un evento de recepción de datos. – jlafay
Esto simplemente no es la forma en que Socket funciona. Comience a diagnosticar esto quitando todos los bloques try/catch. –