Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How use BufferList with SocketAsyncEventArgs and not get SocketError InvalidArgument?

I can use SetBuffer with SocketAsyncEventArgs just fine.

If I try to use BufferList (after doing SetBuffer(null, 0, 0)) I always and immediately get SocketError InvalidArgument (10022) when I do SendAsync on the socket.

There are NO examples or documentation on how to use BufferList and what I am doing makes sense (to me anyway).

Can someone point out an example program or code snippet?

I'm tearing my hair out over this and don't have much left ...

Here is basically what I am doing (e is SocketAsyncEventArgs and lSocket is the same socket I use for SetBuffer which works)

// null the buffer since we will use a buffer list
e.SetBuffer(null, 0, 0);

// create a bufferlist
e.BufferList = new List<ArraySegment<byte>>();

// create the bufferlist with the network header and the response bytes
e.BufferList.Add(new ArraySegment<byte>(lTxBytes)); // add the 4 character total length
e.BufferList.Add(new ArraySegment<byte>(Encoding.ASCII.GetBytes(lTx.Identity))); // echo back the incoming sequence number
e.BufferList.Add(new ArraySegment<byte>(Encoding.ASCII.GetBytes(lResponse)));

// *** the SendAsync always completes IMMEDIATELY (returns false) gets SocketError InvalidArgument (10022)

if (lSocket.SendAsync(e) == false)
{
      // data was already sent back to the client.
      AppSupport.WriteLog(LogLevel.Flow, "ProcessReceive had SendAsync complete synchronously (bytes transferred {0}).", e.BytesTransferred);
      ProcessSend(e);
}
like image 999
Dave Avatar asked Aug 05 '12 22:08

Dave


1 Answers

The reason you are getting an exception is that under the hood the SocketAsyncEventArgs only uses the buffers present in the list at the time of setting the BufferList property. Basically you are trying to send en empty buffer with the code :

e.BufferList = new List<ArraySegment<byte>>();   
e.BufferList.Add(new ArraySegment<byte>(lTxBytes));
e.BufferList.Add(new ArraySegment<byte>(Encoding.ASCII.GetBytes(lTx.Identity)));
e.BufferList.Add(new ArraySegment<byte>(Encoding.ASCII.GetBytes(lResponse)));

Instead try to do :

var list = new List<ArraySegment<byte>>();
list.Add(new ArraySegment<byte>(lTxBytes));
list.Add(new ArraySegment<byte>(Encoding.ASCII.GetBytes(lTx.Identity)));
list.Add(new ArraySegment<byte>(Encoding.ASCII.GetBytes(lResponse)));
e.BufferList = list;

This behavior is not well documented at all and can only be understood by looking at the BufferList setter code in detail. Behind the scenes the SocketAsyncEventArgs has a WSABuffer array field(for interop with native code) where it copies and pins the byte arrays references when you set the BufferList. Since it is this WSABuffer[] that is sent to native code, that explains why your code throws an exception.

like image 51
JJ15k Avatar answered Oct 19 '22 08:10

JJ15k