On 16/03/2018 08:04, Thomas Quarendon wrote:
I've got a boost::asio based server, and generally it's working well. The server runs multiple threads, each simply running the io_service::run method on the same io_service object. It accepts multiple connections and processes multiple concurrent sockets. It uses a strand per connection to ensure that the data for each connection is processed strictly sequentially.
For various reasons it uses a mixture of async and sync reads. The trouble I'm having is implementing a timeout on the synchronous (blocking) reads. I want to protect the server in the case of a client sending an erroneous or malicious packet for example, and make sure a read doesn't block forever. This is probably going to seem like an overly flippant answer, but I do firmly believe that it is the *only* correct answer.
Don't mix async and sync. Once you go async, you have to go async "all the way down". This means that your async handlers must never make blocking calls themselves. If your sync and async operations are both on the same socket, then you must convert them all to async -- if you don't like the async-callback code style that results, look into the coroutine style instead, which looks more like sync code while still behaving like async code. If your sync calls operate on different objects and you can't convert those blocking calls to async calls (eg. they're calling some library API that doesn't provide async), then you should make a "sync worker thread" that has its own separate io_service, and have your async workers post jobs to this service, then post back completions to the original io_service once the task is done. It's up to you how many of these sync worker threads to create, ranging from one global one (easy but will make everything wait for everyone else's blocking operations), through to a small threadpool, through to one per connection (also easy but risks thread explosion). There's no One True Answerâ„¢, it will depend on your application's expected workload and connection count.