[asio] Grasping the proto-typical socket server
Hello, I've dealt with sockets, and socket servers, in the past, so am familiar with them. Abstracting out a prototypical server details, drawing from the plethora of examples, this is what I can determine. I see three primary abstractions, the server itself, with endpoint binding, socket connection acceptor, so far so good. Then there's a connection, which is a sort of io_service to socket adapter. Followed closely by a session concern, where reads and writes are actually performed. Studying the examples, however, it seems to me that by design io_service wants to be *the* first class citizen that runs, with asynchronous callbacks being the mode of choice. How might we go about mixing this code, presumably in the main thread (?), with any worker service-oriented thread that might be going on. For instance, I start a thread and wait for it to finish and rejoin for a main service loop. Socket connection sessions are secondary to this service behavior taking place IMO. If a client connects, great, we'll interact with it. If not, that should be transparent to the application. Possibly session is a second thread worker with a thread-local-scope io_service, that we pub/sub messages to the main service loop. Thoughts on this type of approach? Much appreciated... Regards, Michael
Michael Powell
I see three primary abstractions, the server itself, with endpoint binding, socket connection acceptor, so far so good. Then there's a connection, which is a sort of io_service to socket adapter. Followed closely by a session concern, where reads and writes are actually performed.
Studying the examples, however, it seems to me that by design io_service wants to be *the* first class citizen that runs, with asynchronous callbacks being the mode of choice.
Well, the ASIO examples would stress this aspect. I don't believe it's required, however, and I feel that there is plenty of work that can be done before and after io_service::run() is called.
How might we go about mixing this code, presumably in the main thread (?), with any worker service-oriented thread that might be going on. For instance, I start a thread and wait for it to finish and rejoin for a main service loop.
Fundamentally, you are welcome to do io_service::run in only one thread amongst all the threads running in your project. (See below -- I actually have a multitude of io_services running, but not at all one-to-one with threads!)
Socket connection sessions are secondary to this service behavior taking place IMO. If a client connects, great, we'll interact with it. If not, that should be transparent to the application. Possibly session is a second thread worker with a thread-local-scope io_service, that we pub/sub messages to the main service loop.
Thoughts on this type of approach?
The following architecture is working fairly well for me: 1. Main thread: handles setup, launching primary service threads (data acquisition, data writer, web server, scheduler, usb monitor, etc), and cleanup after the main threads are done. 2. Web server: one thread is the "server thread" and handles all connection listening / accepts. The server code also starts a number of client threads, which exist to service individual client requests. 3. If a client request affects other parts of the system, then that other part is notified in some thread-safe manner (atomics, work queues, etc) I would probably do things a little differently now, but I was lead down this path because this device has a "soft real-time". As such, I didn't want to mix tasks servicing the acquisition interrupt (10s of milliseconds tolerance) with tasks handling, e.g., the web UI or the FTP client (dozens of seconds tolerance). Now that I have a better grasp of how threads and ASIO can interact, I could probably reduce the number of threads I'm running and just schedule various bits of work against a thread pool. Too late to change this design, though. Not the only way to do it, but neither is the methods used in the ASIO examples. In particular, there's nothing keeping you from starting a dozen threads but only calling io_service::run() in six of them. Hope this helps. Best regards, Anthony Foiani
participants (2)
-
Anthony Foiani
-
Michael Powell