Reputation: 964
I'm dealing with socket programming in C#. I need to build a client application which is communicating with a server with given protocol.
I successfully implemented an asynchronous send method, but I'm having troubles in implementing a receive algorithm. The synchronous receive method is working fine.
First of all, I need to continuously read incoming messages and ACK them. To be correct, every received message must have a terminator (0x0c)
I built a multithreading class called MessageFlow with three thread: one takes care of sending messages, the other takes care of receiving messages, the third one takes care of interpreting the received messages and do something.
The worker function for the receiving thread look like this
private void ReadSocketWorker()
{
while (this.canRun)
{
xComClient.Receive();
xComClient.receiveDone.WaitOne();
Thread.Sleep(10);
}
}
XComClient is my class having the socket and all the methods to send and receive messages.
public void Receive()
{
try
{
StateObject state = new StateObject();
state.workSocket = socketClient;
socketClient.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0, new AsyncCallback(ReceiveCallback), state);
}
catch (Exception e)
{
throw e;
}
}
private void ReceiveCallback(IAsyncResult ar)
{
try
{
StateObject state = (StateObject)ar.AsyncState;
Socket client = state.workSocket;
// Read data from the remote device.
int iReadBytes = client.EndReceive(ar);
if (iReadBytes > state.GetBufferSize())
{
byte[] bytesReceived = new byte[iReadBytes];
Buffer.BlockCopy(state.buffer, 0, bytesReceived, 0, iReadBytes);
state.responseList.Enqueue(bytesReceived);
client.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0,
new AsyncCallback(ReceiveCallback), state);
}
else
{
byte[] bytesReceived = new byte[iReadBytes];
Buffer.BlockCopy(state.buffer, 0, bytesReceived, 0, iReadBytes);
state.responseList.Enqueue(bytesReceived);
BuildReceivedMessage(state);
receiveDone.Set();
}
}
catch (Exception e)
{
throw e;
}
}
public class StateObject
{
public Socket workSocket = null;
public const int BufferSize = 20480;
public byte[] buffer = new byte[BufferSize];
public Queue<byte[]> responseList = new Queue<byte[]>();
public int GetBufferSize()
{
return BufferSize;
}
}
What am I doing wrong?
Upvotes: 1
Views: 5520
Reputation: 101176
Your design is a hybrid of synchronous and asynchronous programming. Properly designed async classes do not need to use any threads at all, but let .NET manage the threads.
I really hope that throw e;
is only in the example. Since it's destroying the stack trace (and therefore hiding where the exception ocurred). You can read my article Don't catch that exception and my other articles tagged exceptions
A receive method can look like this:
void OnReceive(IAsyncResult ar)
{
AppendInternalReadBuffer();
CheckInternalReadBufferForMessageAndProcessIt();
ReadAgain();
}
That will block the server from proccessing more than one message at a time per client. If you don't want to do that (which complicates things) you can just use the ThreadPool
in CheckInternalReadBufferForMessageAndProcessIt
.
Upvotes: 1
Reputation: 311023
There really isn't any point in using asynchronous I/O in a thread that has nothing else to do. I would reconsider this design decision.
Upvotes: 2