If you use TCP, then you will definitely have to have one socket for each client on the server side, as well as a socket for listening to connections. For UDP, you can do it all with one socket. Regardless, do the following for your single UDP socket or for each client TCP socket:
You have BeginReceive at any time and BeginWrite when the necessary event occurs (i.e. the user presses a button or a message appears stating that you need to do something).
EDIT: in response to your comment, the way I would handle this would be to include the request id in your header. Whenever sending a request (from either end) includes a unique value for this message. Use Dictionary<RequestId, RequestState> (with appropriate type substitutions) and see if the incoming message is associated with a previously existing request. In addition, you can specify that all identifiers with a high set of bits are requests coming from the client and identifiers with a high bit cleared from the server to avoid conflicts:
Server Client Request 0x00 -------------> Starts processing Starts processing <------- (unrelated) Request 0x80 Request 0x00 complete <---- Sends response to 0x00 Sends response to 0x80 ---> Request 0x80 complete
This is a system that uses the AOL OSCAR protocol for (possibly slow) state requests.
EDIT2: Hm, okay ... do you really want to block it? Something you could do is have a separate thread handling Send / Receive calls. This thread will communicate with the main thread through the thread-safe queue "send message" and a similar "received message" psuedo-queue. The reason I call psuedo last queue is because you would like the ability to output messages from the queue from the queue. The main thread places the message in the send queue, and then blocks the receive queue. Each time the socket stream updates the receive queue, the main stream wakes up and checks if there is a message that it wants. If this is the case, then it will be required (out of order) to complete the desired operation. If the message does not already exist, it will simply be blocked in the queue. When the operation is completed, it will only resume normal operation and receive messages in the queue from the receive queue and process them or do something else.
Does that make sense? I apologize if this is confusing ...
source share