Search code examples
c#.netsocketsasynchronousduplex

Async socket - Duplex communication with permanent sockets in c#


I'm trying to do asynchronous socket communication, and want the server to keep a list of all connected sockets, so he can broadcast messages to them.

First I took the examples from msdn Asynchronous Socket Server and altered them a little so they don't close the sockets. (just removed the .shutdown and .Close commands)

But doing so, seems to cause the client to hang in the "receiving part".

Here are the changes I made to the msdn examples:

Client:

only changed ReceiveCallback() so it stays in an endless receiving loop:

private static void ReceiveCallback(IAsyncResult ar)
{
    try
    {
        // Retrieve the state object and the client socket 
        // from the asynchronous state object.
        StateObject state = (StateObject)ar.AsyncState;
        Socket client = state.workSocket;

        // Read data from the remote device.
        int bytesRead = client.EndReceive(ar);

        if (bytesRead > 0)
        {
            // There might be more data, so store the data received so far.
            state.sb.Append(Encoding.ASCII.GetString(state.buffer, 0, bytesRead));

            // Get the rest of the data.
            client.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0,
                new AsyncCallback(ReceiveCallback), state);
        }
        else
        {
            // All the data has arrived; put it in response.
            if (state.sb.Length > 1)
            {
                response = state.sb.ToString();
                Console.WriteLine(state.sb.ToString());
            }
            // Signal that all bytes have been received.
            receiveDone.Set();

            // Get the rest of the data.
            client.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0,
                new AsyncCallback(ReceiveCallback), state);
        }
    }
    catch (Exception e)
    {
        Console.WriteLine(e.ToString());
    }
}

The Server: just commented out the lines that close the socket:

//handler.Shutdown(SocketShutdown.Both);
//handler.Close();

Later i planed to keep a List of Sockets so i can send Messages to them, but it already fails here.

I'm greatfull for any hints, also I would like to hear your opinion on using this tenique for a server that has to serve at max 100 clients, which could send a request any 2 seconds. (The communication should be both ways, so that the client and the Server can send a Message at any time without waiting for a Message to respond to).

Thank you and good evening Martin


Solution

  • EndReceive only returns 0 when the socket is closed. Your clients will never set the receiveDone handle because the server never closes the socket. The callback is called when data is received OR when the connection is terminated.

    You need to detect the end of message (like the example you linked too). eg. (Modified version of the code you linked)

    content = state.sb.ToString();
    if (content.IndexOf("<EOF>") > -1) {
         // All the data has been read from the 
         // client. Display it on the console.
         Console.WriteLine("Read {0} bytes from socket. \n Data : {1}",
                     content.Length, content );
         // Echo the data back to the client.
         Send(handler, content);
    
         { // NEW 
             // Reset your state (persist any data that was from the next message?)      
    
             // Wait for the next message.
             handler.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0, 
             new AsyncCallback(ReadCallback), state);
         }
    
     } else {
          // Not all data received. Get more.
          handler.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0, 
          new AsyncCallback(ReadCallback), state);
    }