Async sockets, receive callback problem

Hi,

I'm writing an async socket server that transport custom serialized objects. However, I ran into a problem when sending a lot of messages in a loop from the server to the client. To simplify matters I shortened my test code:
Here I'm sending some data to the client...


for(int i = 0; i < 100; i++)
{
state.WorkSocket.BeginSend(b, 0, b.Length, SocketFlags.None, sendCallback, state);
}

 


The client receives the data and processes it:

                StateObject state = (StateObject)ar.AsyncState;
                i = state.WorkSocket.EndReceive(ar);

                if (i == 0)
                {
                    state.WorkSocket.Shutdown(SocketShutdown.Both);
                    state.WorkSocket.Close();
                }
                else
                {
                    state.MemoryStream.Write(state.Buffer, 0, i);
                    state.Buffer = new byte[StateObject.BufferSize];
                    MessageHandler.Handle(state);
                    state.MemoryStream.Close();
                    state.MemoryStream = new MemoryStream();
                    state.WorkSocket.BeginReceive(state.Buffer, 0, state.Buffer.Length, SocketFlags.None, receiveCallback, state);
                }

 


However, here's the problem ... since the data is sent from the server very quickly and the socket doesn't block, I receive the data faster than it is processed, thus causing the MemoryStream filling up with data before I can close it.
What I'd like is that my ReceiveCallback method only may be called when I actually call WorkSocket.BeginReceive.
What's the best way to go about this

Thanks



Answer this question

Async sockets, receive callback problem

  • imyousuf

    hm, not sure how I explain that properly....
    the thing is, even when I comment out BeginReceive in the client code, the ReceiveCallback method is called over and over again (100 times in this case). However, the ReceiveCallback never waits until processing the prior callback is finished but it calls directly into the method, thus filling up the MemoryStream with bytes before the code is reached where I clear the MemoryStream. This is because the socket is non blocking I think. Does this make sense

  • stephenstarring

    Hi Malar,

    thanks for you lengthy explanation. However, what I don't understand yet is this...
    The ManualResetEvent signal the main thread to wait, right But I'd like that on a per socket basis. So, I call BeginSend on a socket but I don't want another BeginSend to be called before EndSend for THAT socket is called, right Because otherwise, sending data to all other sockets would wait as well, right

    Thanks,

    Tom

  • wayne_p

    Tom
    Malar has explained the sync/async details. If you have multiple sockets and
    you want to maintain one send at a time you could declare a state object as follows

    class state
    {
       Socket s;
       AutoResetEvent are = new AutoResetEvent(false);
       ...
    }

    Then in you main loop you could simply send as many sends on different sockets
    and wait for any of the events to get signaled. I believe there is a limit on the
    number of number of events you could wait on.

    In any case you should think about the design of you app so that you don't
    get into these issues. You should be able to send as the data is available
    and receive as the data is available.

    As per the last question, you can receive 0 bytes when the peer
    closes the connection gracefully

  • dev_kh

    I beleive Durga is recommending against serializing your calls to Begin/EndSend for performance reasons as that way you can only service one request at a time. 



  • SAinCA

    You state:

    What I'd like is that my ReceiveCallback method only may be called when I actually call WorkSocket.BeginReceive.
    What's the best way to go about this


    The callback method (delegate) passed to a BeginXXX call (BeginReceive in this case) is called once for each call you make to BeginReceive.  So, in this case, the ReceiveCallback method will only be called once for each call you make to BeginReceive. 

    Please let me know if I am misinterpreting your question.



  • GAT2000

     Malar Chinnusamy wrote:


    I strongly suspect that you have a for loop there .. something like this


    for(int i = 0; i < 100; i++)
    {
    state.WorkSocket.BeginReceive(state.Buffer, 0, state.Buffer.Length, SocketFlags.None, receiveCallback, state);
    }

     


    Yes, you are right about this but I did post that ;)
    That's why I was asking how I can make the server wait to send data to that specific socket until EndSend for that socket has returned

  • CGS

    I think I understand now where the problem is coming from ...
    I'm calling BeginSend from another class:

            public static void Send(ISocketObject socketObject, StateObject state)
            {
                state.MemoryStream = new MemoryStream();
                state.Buffer = new byte[StateObject.BufferSize];

                MemoryStream stream = new MemoryStream();
                BinaryWriter writer = new BinaryWriter(stream);

                socketObject.Write(writer);

                byte[] b = stream.ToArray();
                state.WorkSocket.BeginSend(b, 0, b.Length, SocketFlags.None, sendCallback, state);
            }

     


    so, the BeginSend method is called 100 times without ever waiting on EndSend being called. I guess that's the problem why I get the problem on the client side, am I right
    The question is, how can I make the server code wait for EndSend to be called before another class can call my static Send method again

  • Sudhaks

    Also,

    what I don't understand ... when I look at the async client sample from msdn:

    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();
     }
     // Signal that all bytes have been received.
     receiveDone.Set();
     }

     

    ... they are checking if bytes received > 0 or not. However, in my client/server, I never get a receiveCallback with 0 bytes received

  • mrrogers912

     Durgaprasad Gorti wrote:
    What I was saying is to not serialize the begin and end Send calls


    Hm, sorry I don't quite understand what you mean

    Maybe someone could should shed some more light into this what the best approach for my scenario is in gerneal...
    • Server and client need bidirectional communication
    • Objects should be transported
    • Processing should be async
    • Should hande 500-1000 clients


  • SanthoshKumar

    OK May be I was not clear. You can do serializtion of objects.
    What I was saying is to not serialize the begin and end Send calls



  • renato sabo

    Tom,


    Like Mike said,  the ReceiveCallback method will be called once and only once for each call you make to BeginReceive.    You had mentioned

    >even when I comment out BeginReceive in the client code, the ReceiveCallback >method is called over and over again (100 times in this case). 

    You might want to verify this.. You had pasted the ReceiveCallback section in the client .. How about the place where you had started issuing a beginreceive call..

    I strongly suspect that you have a for loop there .. something like this


    for(int i = 0; i < 100; i++)
    {
    state.WorkSocket.BeginReceive(state.Buffer, 0, state.Buffer.Length, SocketFlags.None, receiveCallback, state);
    }

     



    Send and receive are not synchronized.. Dont expect a receive to be called for every send.. Send might send 1000 bytes in 10 packets, but there is a possibility that receive will get all the 1000 bytes in just 1 call. On a similar note, send might send 1000 bytes in a packet and but you might have to call receive 10 times to read all of them


    Asynchronous calls are nonblocking.. but there is only one endXXX associated with each beginXXX... 
    The beginsend returns immediately... but endSend is the blocking call.. If the send has not completed by the time endsend is called, endsend will block. SendCallback is called only when send is complete. So a endSend inside a SendCallback returns immediately.

    So if you are code is like this
    socket.BeginSend()
    socket.EndSend()

    EndSend will block till send has completed and this defeats the whole purpose of asynchronous programming.. you could have just used synchronous call instead.. If you want only one send to be active at a time and want some work to be done before you call the next send, you can use resetEvents to synchronize them..
    Something like this

    socket.BeginSend(.... sendcallback, ...)
    <do some work.. before next beginsend is called>

    resetEvent.WaitOne() // wait till beginsend completes and sendcallback is called
    socket.BeginSend(.... sendcallback, ...) //issue the next send


    In the sendcallback

    ... sendcallback(..)
    {
    //get socket
    socket.EndSend();
    //do work
    resetEvent.Set();
    }

    Hope this helps









  • New User1

    Hi,

    so, when I was to use AutoResetEvent how would the following scenario be handled:
    Assuming I have 10 sockets connected and then start a for loop to send data to each of the 10 sockets. Would data be sent to each of the 10 sockets one by one but simultaneously to the 10 sockets or would data be sent to the first socket then waits until endsend and sends data 1 to second socket, etc.

    Also, instead of using AutoResetEvent, would it be better to check for a specific byte constellation in receive and handle the message when that constellation is found That way I wouldn't have to wait for sends to complete, right What about using a 10 byte long "terminator"  and check every 10th position for the specific byte, if it matches I also check the previous 9 bytes if it's really the terminator. That way it should be pretty fast


  • davenitup

    hm, rather than going that route I'd like to find a way to not send unless EndSend was called I don't see what's wrong with serializing the objects. The way I'm doing it now is very comfortable and I can encrypt specific properties of my ISocketObject that store sensitive information while serializing them. The other side simply pulls the first int from the MemoryStream which represents an enum with the object type. So, it's very easy to send objects over the net

  • Fortey

    I think it is better not to serialize. I woud say that You can put the memory stream bytes in a way that can accommadate multiple callbacks. For example, they can create a new memory stream and add it to a list. The processing happens in the background and when you complete consuming the bytes, you can disppse the memory stream.

  • Async sockets, receive callback problem