First of all. Locking is all bad when it comes to socket programming. @AndrewKeith's solution is quite good for queuing commands and to send them.
What you need is to have a request id that you can put in another queue and send it back with the response. You can have several ongoing commands by doing so.
Simple pseudo code:
public void Send(ICommand command)
{
var myPacket = new CommandPacket {
Command = command,
RequestId = Guid.NewGuid()
};
_pendingCommands.Add(myPacket);
var buffer = Serialize(myPacket);
socket.Send(buffer);
}
public void OnReceive(IAsynResult ar)
{
var bytesRead = socket.EndRecieve(ar);
_inStream.Write(_readBuffer, 0, bytesRead);
if (GotCompletedPacket(_inStream))
{
var packet = Deserialize(_inStream);
var waitingCommand = _pendingCommands.FirstOrDefault(p => p.RequestId == packet.RequestId);
if (waitingCommand != null)
//got a reply to the command.
}
}
I would personally add a delegate when invoking the command:
public void Send(ICommand command, ICommandHandler handler)
and invoke that handler when a reply have been received.