I have a multithreaded TCP server that must rely on synchronous communication (blocking I/O). Each connected client to the server runs in its own separate thread. Each thread must be able to communicate with each other by sending “messages” to one another. Additionally, some events must occur at a timed interval (such as, if a client hasn’t authenticated itself in three minutes, it will be shown an error message and be disconnected.)
How I solved this in Delphi is to have the blocking read operation on each socket time out every 500 milliseconds and that’s when I’d check to see if any scheduled events were supposed to take place. I’d also check the client thread’s queue to see if any other threads left “messages” for that client and then process them. Then I’d block for 500 more milliseconds until some data arrives, and so on.
When porting this application to .NET, I am having some trouble because all of the socket blocking is done at a lower level. I can’t use the blocking operation iterations of the socket to check my queue or check for scheduled events. I’d much rather separate socket operations from my application logic anyway, but I need a strategy to allow me to both block socket operations and check my queue and timed events.
How do I go about this one? I could set the socket to have a receive timeout every 500ms, but then an exception is created if the socket times out. But I’m not timing out the socket to disconnect it, simply to interrupt it for a while so I can check my queue and do other stuff. So I’d loop again. That means potentially countless exceptions are created and caught per thread, and that’s not good for performance.
I tried peeking the socket, but that causes a noticeable delay to the client and it becomes difficult to tell when the socket has suddenly disconnected. This is due to the fact that I must call a Receive() eventually to tell if the socket’s still there, and that will block indefinitely.
What are my options? I don’t even really want to have a queue of messages at all, I’d much rather have them event driven this time so I don’t have to poll to check for messages. But this is complicated in a multithreaded application because events are handled by the same thread that triggered them. That particular problem was easy to solve in a GUI application with Control.Invoke(), but this is not a GUI application.