lsalzman / enet

ENet reliable UDP networking library
MIT License
2.71k stars 669 forks source link

Round trip time varies with update rate #194

Closed xissburg closed 2 years ago

xissburg commented 2 years ago

Consider the following: if enet_host_service is called once every second (in a while loop, as usual) in one end while the other end is producing packets every 100ms, with no network jitter, the enet_host_service loop should run 10 times thus consuming 10 packets. In the receiving end, it looks as if all packets had arrived at the same time, but on a system level, they have all arrived within 100ms of one another. Do the system calls and structures provide any information about the time a packet arrived? This information is important when measuring relative time quantities such as RTT and synchronizing clocks. Is the only solution to call enet_host_service at a higher rate or even have a dedicated networking thread which calls enet_host_service with no timeout, thus processing incoming packets as quickly as possible?

The issue described above seems to be the reason why ENetPeer::roundTripTime decreases as the client and server update rates go up (e.g. disabling vsync on the client). If a ping packet arrives right after the enet_host_service loop is done, it will only be processed in the next update (e.g. 16ms later) and the pong will be sent back with a significant delay, thus causing the RTT calculations to be imprecise. At the same time, if the ping packet arrives when enet_host_service is called, the pong with be sent immediately. If the client and server are running on the same machine, it looks like you'd have ping-pong sequences that take 16ms while the next one takes near 0ms, thus resulting in large variance.

lsalzman commented 2 years ago

Calling enet_host_service once a second won't work well at all. Ideally, it's meant to be called every frame within a game loop. This is by design.

xissburg commented 2 years ago

Calling it once a second was just a contrived example to illustrate my point. Just use a smaller number and it will be the same.

lsalzman commented 2 years ago

For game usage it is adequate to just call it at your game framerate, i.e. 30-60 HZ or similar.

xissburg commented 2 years ago

I know that, and it looks like you did not read my question at all. I am asking about the precise calculation of the time a packet has arrived.

lsalzman commented 2 years ago

I don't believe you can get timing information from the recvmsg syscall. Your best bet is to call it as often as possible. That's how it's designed to work. It is understood that if you don't call it often you will see corresponding granularity effects in the RTT since the timing of everything is determined by how often you call it.

mman commented 2 years ago

Hi Lee,

I think I may have seen a similar issue as the original poster, which relates to how is the PL and RTT computed when the peer connection breaks and we start loosing reliable/unreliable/ping packets.

During that window when the packets are starting to be lost the RTT and PL values represent the last “good” values and do not indicate that there is a problem with the peer. And that lasts for 15/30 seconds depending on your timeout configuration until the peer is eventually disconnected. And from my experience it does not matter how often you call enet_host_service. Is my understanding correct?

I think (but I may be mistaken as I do not known the code well) this is because the PL and RTT are recomputed only when the ping or reliable packet is received?

My expectation as a user of the library would be that PL and RTT should start increasing with every tick of enet_host_service when a peer becomes dead, but not yet disconnected.

Imagine kids playing a game, where one peer will timeout, but for others still looks as alive (good RTT and PL values) despite being dead and despite the fact that it will disconnect in say 15 seconds.

So the solution could be to recompute PLL and RTT on every enet_host_service taking into account “expected” incoming pings from the peer and properly indicate that PL and RTT are increasing should the expected ping packets be missing.

Do I understand it right? Martin

On 6. 3. 2022, at 9:00, Lee Salzman @.***> wrote:

I don't believe you can get timing information from the recvmsg syscall. Your best bet is to call it as often as possible. That's how it's designed to work. It is understood that if you don't call it often you will see corresponding granularity effects in the RTT since the timing of everything is determined by how often you call it.

— Reply to this email directly, view it on GitHub https://github.com/lsalzman/enet/issues/194#issuecomment-1059914655, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAB47VVNKGJTXQTXZM3SEGLU6RQ2LANCNFSM5QAX5FRQ. Triage notifications on the go with GitHub Mobile for iOS https://apps.apple.com/app/apple-store/id1477376905?ct=notification-email&mt=8&pt=524675 or Android https://play.google.com/store/apps/details?id=com.github.android&referrer=utm_campaign%3Dnotification-email%26utm_medium%3Demail%26utm_source%3Dgithub. You are receiving this because you are subscribed to this thread.