.NET C # Synchronous Reception Doesn't Block

I recently tackled the weird behavior of the synchronous .Net receive method. I needed to write an application that has nodes that communicate with each other, sending / receiving data. Each server has a receive loop that is synchronous, after receiving a serialized class, it deserializes and processes it. After that, it asynchronously passes this serialized class to some selected nodes (using AsynchSendTo).

MSDN clearly states that:

"If you use a socket-oriented Socket, the Receive method will read as much data as is available, up to the size of the buffer. If the remote host disconnects the Socket connection with the shutdown method and all available data, the receive method will end immediately and return zero bytes."

In my case, this is not the case. There are some random cases when Receive does not block and returns 0 bytes (without a deterministic situation) immediately after the connection is established. I am 100% sure that the sender sent up to 1000 bytes. Another fun fact: when you install Sleep (500), before everything works out, everything works fine. The following is the reception code:

_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); } 

Also sending part:

 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; } 

My question is: am I using synchronous reception incorrectly? Why doesnโ€™t it block the event, although there is data to receive?

+6
source share
2 answers

You shoot in the foot.

 bytesRec = handler.Receive(bytes, totalBytes, handler.Available, SocketFlags.None); 

At the very beginning of the connection, Available will be 0, forcing it to immediately return from 0. Instead, you should specify the number of free bytes in your buffer (for example, bytes.Length-totalBytes ), then it will also be blocked.

+4
source

You may have a problem with concurrency. After you accept the connection, you jump right into the reception. The sender process may not have enough time to complete the call to send, so your handler.Available is 0 and returns.

This is why an โ€œerrorโ€ does not occur if you add to sleep 500 ms.

+6
source

Source: https://habr.com/ru/post/901713/


All Articles