What is stopping data flow with .NET 3.5 asynchronous System.Net.Sockets.Socket?

Posted by TonyG on Stack Overflow See other posts from Stack Overflow or by TonyG
Published on 2010-05-26T00:43:30Z Indexed on 2010/05/26 0:51 UTC
Read the original article Hit count: 320

I have a .NET 3.5 client/server socket interface using the asynchronous methods. The client connects to the server and the connection should remain open until the app terminates. The protocol consists of the following pattern:

  1. send stx
  2. receive ack
  3. send data1
  4. receive ack
  5. send data2 (repeat 5-6 while more data)
  6. receive ack
  7. send etx

So a single transaction with two datablocks as above would consist of 4 sends from the client. After sending etx the client simply waits for more data to send out, then begins the next transmission with stx. I do not want to break the connection between individual exchanges or after each stx/data/etx payload.

Right now, after connection, the client can send the first stx, and get a single ack, but I can't put more data onto the wire after that. Neither side disconnects, the socket is still intact. The client code is seriously abbreviated as follows - I'm following the pattern commonly available in online code samples.

private void SendReceive(string data) {
    // ...
    SocketAsyncEventArgs completeArgs;
    completeArgs.Completed += new EventHandler<SocketAsyncEventArgs>(OnSend);
    clientSocket.SendAsync(completeArgs);
    // two AutoResetEvents, one for send, one for receive
    if ( !AutoResetEvent.WaitAll(autoSendReceiveEvents , -1) )
       Log("failed");
    else
       Log("success");
    // ...
}
private void OnSend( object sender , SocketAsyncEventArgs e ) {
// ...
    Socket s = e.UserToken as Socket;
    byte[] receiveBuffer = new byte[ 4096 ];
    e.SetBuffer(receiveBuffer , 0 , receiveBuffer.Length);
    e.Completed += new EventHandler<SocketAsyncEventArgs>(OnReceive);
    s.ReceiveAsync(e);
// ...
}
private void OnReceive( object sender , SocketAsyncEventArgs e ) {}
    // ...
    if ( e.BytesTransferred > 0 ) {
        Int32 bytesTransferred = e.BytesTransferred;
        String received = Encoding.ASCII.GetString(e.Buffer , e.Offset , bytesTransferred);
        dataReceived += received;
    }
    autoSendReceiveEvents[ SendOperation ].Set(); // could be moved elsewhere
    autoSendReceiveEvents[ ReceiveOperation ].Set(); // releases mutexes
}

The code on the server is very similar except that it receives first and then sends a response - the server is not doing anything (that I can tell) to modify the connection after it sends a response. The problem is that the second time I hit SendReceive in the client, the connection is already in a weird state.

Do I need to do something in the client to preserve the SocketAsyncEventArgs, and re-use the same object for the lifetime of the socket/connection? I'm not sure which eventargs object should hang around during the life of the connection or a given exchange.

Do I need to do something, or Not do something in the server to ensure it continues to Receive data?

The server setup and response processing looks like this:

void Start() {
    // ...
    listenSocket.Bind(...);
    listenSocket.Listen(0);
    StartAccept(null); // note accept as soon as we start. OK?
    mutex.WaitOne();
}
void StartAccept(SocketAsyncEventArgs acceptEventArg) {
    if ( acceptEventArg == null )
    {
        acceptEventArg = new SocketAsyncEventArgs();
        acceptEventArg.Completed += new EventHandler<SocketAsyncEventArgs>(OnAcceptCompleted);
    }
    Boolean willRaiseEvent = this.listenSocket.AcceptAsync(acceptEventArg);
    if ( !willRaiseEvent )
        ProcessAccept(acceptEventArg);
    // ...
}
private void OnAcceptCompleted( object sender , SocketAsyncEventArgs e ) {
    ProcessAccept(e);
}
private void ProcessAccept( SocketAsyncEventArgs e ) {
    // ...
    SocketAsyncEventArgs readEventArgs = new SocketAsyncEventArgs();
    readEventArgs.SetBuffer(dataBuffer , 0 , Int16.MaxValue);
    readEventArgs.Completed += new EventHandler<SocketAsyncEventArgs>(OnIOCompleted);
    readEventArgs.UserToken = e.AcceptSocket;
    dataReceived = ""; // note server is degraded for single client/thread use
    // As soon as the client is connected, post a receive to the connection.
    Boolean willRaiseEvent = e.AcceptSocket.ReceiveAsync(readEventArgs);
    if ( !willRaiseEvent )
        this.ProcessReceive(readEventArgs);
    // Accept the next connection request.
    this.StartAccept(e);
}
private void OnIOCompleted( object sender , SocketAsyncEventArgs e ) {
    // switch ( e.LastOperation )
    case SocketAsyncOperation.Receive:
        ProcessReceive(e); // similar to client code
        // operate on dataReceived here
    case SocketAsyncOperation.Send:
        ProcessSend(e); // similar to client code
}
// execute this when a data has been processed into a response (ack, etc)
private SendResponseToClient(string response) {
    // create buffer with response
    // currentEventArgs has class scope and is re-used
    currentEventArgs.SetBuffer(sendBuffer , 0 , sendBuffer.Length);
    Boolean willRaiseEvent = currentClient.SendAsync(currentEventArgs);
    if ( !willRaiseEvent )
        ProcessSend(currentEventArgs);
}

A .NET trace shows the following when sending ABC\r\n:

Socket#7588182::SendAsync()
Socket#7588182::SendAsync(True#1)
Data from Socket#7588182::FinishOperation(SendAsync)
00000000 : 41 42 43 0D 0A
Socket#7588182::ReceiveAsync()
Exiting Socket#7588182::ReceiveAsync()         -> True#1

And it stops there. It looks just like the first send from the client but the server shows no activity.

I think that could be info overload for now but I'll be happy to provide more details as required.

Thanks!

© Stack Overflow or respective owner

Related posts about sockets

Related posts about asynchronous