Question

I am trying to understand the 'SocketAsyncEventArgs' class in C#. http://msdn.microsoft.com/en-us/library/system.net.sockets.socketasynceventargs.aspx

I am following this tutorial: http://www.codeproject.com/Articles/83102/C-SocketAsyncEventArgs-High-Performance-Socket-Cod

Now I am stuck into how I exactly should process data with my server. What I am trying to do is use a SocketAsyncEventArgs for a connected client with an allocated Buffer space of 512 bytes in the BufferManager. Then what I want to do is to decode the byte[] data into my own custom class (ClientPacket) which holds the byte[] for decoding and reading from.

This is all well but my server doesn't always respond with data the question is:

Do I use 1 SocketAsyncEventArgs for the receiving and loop around to process receive data, then allocate a SocketAsyncEventArgs from the pool whenever I need to send then return it on completion?

And how does the SocketAsyncEventArgs know when reading is complete? (when it is finished with the byte[] buffer before it over-writes it with new data) like how is it returned to the pool when done if I don't respond back?

Was it helpful?

Solution

I only use one SocketAsyncEventArgs instance for all of my needs. I simply reset the buffer between each request (by setting it to a new Byte[]).

Once I have connected and have a reference to the Socket, I start listening like this:

public void StartListening(SocketAsyncEventArgs e)
{
    ResetBuffer(e);
    e.Completed += SocketReceive;

    socket.ReceiveAsync(e);
}

I have a helper function that resets the buffer:

private void ResetBuffer(SocketAsyncEventArgs e)
{
    var buffer = new Byte[SocketBufferSize];

    e.SetBuffer(buffer, 0, SocketBufferSize);
}

I process the data like:

private void SocketReceive(Object sender, SocketAsyncEventArgs e)
{
    ProcessData(e.Buffer, 0, e.BytesTransferred);

    ResetBuffer(e);

    socket.ReceiveAsync(e);
}

In ProcessData, you can use the byte array as needed to pull in the data. I use it to create a MemoryStream which I then deserialize into my class (similar to ClientPacket), as follows:

private void ProcessData(Byte[] data, Int32 count)
{
    using (var stream = new MemoryStream(data, 0, count))
    {
        var serializer = new XmlSerializer(typeof(ClientPacket));

        var packet = serializer.Deserialize(stream);

        // Do something with the packet
    }
}

As for your last question. The framework handles everything to do with the underlying TCP protocol, etc. so you can rely on the event handler being called whenever there is data to be processed. Use the e.BytesTransferred value to indicate the amount of data you actually received which may be smaller than but will never exceed your buffer size (SocketBufferSize in my code). If the message was larger than the buffer size, the TCP infrastructure will buffer the messages and send them to you in chunks based on SocketBufferSize (by raising the event once for each chunk). If this is a concern, simply increase SocketBufferSize until the majority of your message are received in one chunk.

The downside of the chunking is that messages may be merged by the infrastructure which means that you may need a way to tell when the first message has ended. Typical approaches include prefacing your message with a 4 byte integer that indicates the message length. I can elaborate more if needed.

Hope that helps.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top