static void OnReceive(IAsyncResult ar)
{
ReadMessageAsyncState state = ar.AsyncState as ReadMessageAsyncState;
try
{
int count = state.userSocket.EndReceive(ar);
state.bytesReceived += count;
if (state.messageSize == -1)//we are still reading the size of the data
{
if (count == 0)
throw new ProtocolViolationException("The remote peer closed the connection while reading the message size.");
if (state.bytesReceived == 4)//we have received the entire message size information
{
//read the size of the message
state.messageSize = BitConverter.ToInt32(state.buffer, 0);
if (state.messageSize < 0)
{
throw new ProtocolViolationException("The remote peer sent a negative message size.");
}
//we should do some size validation here also (e.g. restrict incoming messages to x bytes long)
state.buffer = new Byte[state.messageSize];
//reset the bytes received back to zero
//because we are now switching to reading the message body
state.bytesReceived = 0;
}
if (state.messageSize != 0)
{
//we need more data - could be more of the message size information
//or it could be the message body. The only time we won't need to
//read more data is if the message size == 0
state.userSocket.BeginReceive(state.buffer,
state.bytesReceived, //offset where data can be written
state.buffer.Length - state.bytesReceived, //how much data can be read into remaining buffer
SocketFlags.None, new AsyncCallback(OnReceive), state);
}
else
{
//we have received a zero length message, notify the user...
ReadMessageEventArgs args = new ReadMessageEventArgs(String.Empty);
state.userCallback(args);
state.Dispose();
}
}
else //we are reading the body of the message
{
if (state.bytesReceived == state.messageSize) //we have the entire message
{
//notify the user
state.userCallback(new ReadMessageEventArgs(Encoding.ASCII.GetString(state.buffer)));
//free up our reference to the socket, buffer and the callback object.
state.Dispose();
}
else //need more data.
{
if (count == 0)
throw new ProtocolViolationException("The remote peer closed the connection before the entire message was received");
state.userSocket.BeginReceive(state.buffer,
state.bytesReceived, //offset where data can be written
state.buffer.Length - state.bytesReceived, //how much data can be read into remaining buffer
SocketFlags.None, new AsyncCallback(OnReceive), state);
}
}
}
catch (Exception ex)
{
ReadMessageEventArgs args = new ReadMessageEventArgs(ex);
state.userCallback(args);
state.Dispose();
}
}