Anyway, your question of latency is interesting. If you get data "right away" in the receive thread, what would the rest of your program do with it? If you have another thread that does simulation, the data you receive would have to wait for that thread to simulate response anyway. And if that's the case, why wouldn't you just poll the network in the simulation thread, right before taking a simulation step?
The emphasis is mine. OP hasn't yet answered why he wants such latency and what he plans on doing with such packets. A blocking socket in its own thread should have the latency you want. The OS-specific routines should give similar results. The question is how can you respond in such low latency. It's pointless to retrieve a packet in 0.1ms intervals if you're not going to use it in the next 16ms; or if processing the packet and preparing a reply takes 10ms. That's why the OS buffers incoming packets to release them all at once to you the next time you read them. Even low latency mouse and keyboard reading at application level works this way.
I think one of the things here is that Enet is designed to be used from a "main loop" that is already frame rate limited. This is because all main loops are already frame rate limited.
You always have some kind of frame rate governor. Tie your Enet usage to that.
For a client, there's the render loop. If you have to block the render loop for more than 5 seconds to load a level, then you are also not providing a good user experience, because progress bars, window switching, and all the rest of the windowing system won't work. Solve that! If you don't want to solve that, then you can at least call the service function occasionally while loading -- say, once per file opened, or something like that.
On the server, you still need a frame rate governor, assuming you have simulation. Typically, there is a fixed simulation step, and you need to use sleeping to rate limit simulation. If you use a variable simulation step rate, then you have to do something to keep the step rate reasonable, no matter whether you use networking or not.
Finally, Sleep() and SleepEx() aren't that great on Windows; they have coarse granularity. It's better to use MsgWaitForObjectEx() with a timeout. This also has the benefit of waking up early if the user tries to interact with the program.
Finally: On windows, when the user is dragging a window around, the main loop is blocked, but messages will be sent to the window message handler, so adding a WM_TIMER timer that ticks every X milliseconds is a good way of taking care of that part of always keeping the application responsive.
Finally: On windows, when the user is dragging a window around, the main loop is blocked, but messages will be sent to the window message handler, so adding a WM_TIMER timer that ticks every X milliseconds is a good way of taking care of that part of always keeping the application responsive.
I get that messages are queued up for the window, but does not the thread that is blocked during dragging prevent it from calling PeekMessage() which will trickle down to WinProc, how will one then tick Enet?
On the server, if it is blocked until it recieves a message then it can't send anything before it recieves a packed right? So if an important event needs to be sent but the server is waiting to recieve a packet, that event will have a latency attached to it?
I get that messages are queued up for the window, but does not the thread that is blocked during dragging prevent it from calling PeekMessage() which will trickle down to WinProc, how will one then tick Enet?
While dragging a window, Windows itself will call the WndProc without dispatching through GetMessage/PeekMessage.
On the server, if it is blocked until it recieves a message then it can't send anything before it recieves a packed right? So if an important event needs to be sent but the server is waiting to recieve a packet, that event will have a latency attached to it?
Correct. That's why you should come up with a determined latency (typically: one fixed time step of 16.667 ms) and, for each time step, drain-network, do-simulation, send-out-events. That way, everything is done on specific time steps. If you want to deviate from this model, you need to have a very good description of what your real goal actually is, and how that deviation actually achieves that goal.