Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

.NET C# Synchronous Receive doesn't block

Recently I have tackled a strange behaviour of .Net synchronous receive method. I needed to write an application that has nodes which communicate with each other by sending/receiving data. Each server has a receipt loop which is synchronous, after receiving a serialized class it deserializes and processes it. After that it sends asynchronously this serialized class to some chosen nodes (using AsynchSendTo).

The MSDN clearly says that:

"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."

In my case it's not true. There are some random cases when the Receive doesn't block and returns 0 bytes (non-deterministic situtation) right away after establishing connection. I'm 100% sure that the sender was sending at lest 1000 bytes. One more funny fact: when putting Sleep(500) before receive everything works just fine. Hereunder is the receiving 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 the 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: am I using the synchronous receive in a wrong way? Why it doesn't block event though there is data to receive?

like image 866
Radek Busz Avatar asked Nov 17 '11 13:11

Radek Busz


People also ask

Is C# and .NET same?

C# is a programming language and . NET is a framework.

Can I use .NET with C?

. NET Framework is an object oriented programming framework meant to be used with languages that it provides bindings for. Since C is not an object oriented language it wouldn't make sense to use it with the framework.

Is .NET basically C#?

In summary, C# is a programming language, while . NET is a developer platform. After comparing C# vs . NET, it is clear that both are essential for application development.

What is C NET programming?

C# (C-Sharp) is a programming language developed by Microsoft that runs on the .NET Framework. C# is used to develop web apps, desktop apps, mobile apps, games and much more. Start learning C# now »


2 Answers

You're shooting yourself 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 return immediately with 0. Instead, you should specify the number of bytes which are free in your buffer (e.g. bytes.Length-totalBytes), then it will also block.

like image 106
Lucero Avatar answered Nov 15 '22 00:11

Lucero


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

This is also why the "bug" does not occur when you add the sleep of 500 ms.

like image 29
Tudor Avatar answered Nov 15 '22 01:11

Tudor