I'm developing a multi-protocol socket server, on my first attempt I made it event driven because it was the best way I knew, but by using this approach I was unable to find an efficient way to link application specific data to the sockets, so on each event I had to perform a search in order to link the socket to its context. After some research I found out IO completion ports were a much better way to do the job, so after a lot of reading I finally was able to remake my code to work under an IOCP approach.
However after some further research I found this article (please read: "Accepting Connections") which recommends to decouple the accept operations from the I/O process by handling the FD_ACCEPT event on a different thread, he also recommends this as a mean to prevent malicious attacks... The explanation does makes sense, but the author does not take into account that under this approach there is no way (at least AFAIK) to link a socket with its context data, so applying this recommendation on a server which listens several ports bound to multiple address and each one handling a different protocol, involves necessarily a search operation on each FD_ACCEPT event, which may (or may not) defeat the original propose of decoupling the accepts... and which was the reason I migrated to completion ports in the first place.
So.. I wonder if having 2 completion ports, one for the accept operations and one for the I/O process can be considered a good practice in general therms, but specially regarding performance... or is it best to have just one?
Update:
After some experimentation I discovered that, to decouple the accept process from the I/O process by using 2 IOCPs (on separated threads) is simply not practical and due to this fact, no efficiency boost can be gained. So, even when he doesn't explicitly mention it, the author is right and the only practical way to decouple this two processes is by handling the FD_ACCEPT event with all which implies, but if he is right in his statements also, then the only way to make it viable in my case, would be to find an efficient way to link each socket to its context data, or in other words; without having to search, so the original question remains.
If you're using IOCP for data flow then it's usually best to use IOCP for accepting new connections, so using
AcceptEx()
is a good idea. Don't bother with the complexity of dealing with also using it to read the first chunk of data from the peer, it's hard to avoid the potential denial of service attack that this opens up and the performance gain is negligible for most server designs. Just use it as an overlapped Accept which saves you having to have a separate accept thread per port and so scales very nicely.Personally I've never used the
FD_ACCEPT
idea that the article you link to suggests. Simply post a newAcceptEx
when one completes and post a configurable number at the start. That way you'll always have 'X' pending accepts.I have some articles and example code here which may help.