Opened 9 years ago
Last modified 8 years ago
#3264 closed enhancement
Better timeout handling — at Version 1
Reported by: | elexis | Owned by: | |
---|---|---|---|
Priority: | Should Have | Milestone: | Alpha 20 |
Component: | Network | Keywords: | patch |
Cc: | Patch: |
Description (last modified by )
Refs #69 Enhance Multiplayer Experience, #2854 Extensive lag may cause disconnections
Problem: When a client drops, the game hangs for up to 30 seconds sometimes. The game appears to be paused and no one knows what's going on (although you can be sure that someone is dropping after like 10 seconds).
Fix: (1) Some seconds after the last turn was processed, a message should be displayed for all clients that we are waiting for. (2) The maximum timeout duration could be reduced from 30 to 10-20 seconds.
Reproduce timeout pauses: Without modifying 0ad, I could reproduce a 5 to 8 second timeout, where the game appears to be paused for that duration. You need to start a game with another client and then kill that client with
kill -9 <pid>
To get the correct process ID use:
pidof pyrogenesis
Or just use this command to kill the 0ad instance with the highest PID (usually the second instance):
kill -9 `pidof pyrogenesis | tr ' ' '\n' | sort -r | head -n 1`
Following the timeout model of enet (see below), the 30 second timeout can only be reproduced if you have actual lag.
Technical Background:
Currently the client network timeouts are not set in 0ad, i.e. the default values of the enet library are used. They are hardcoded in enet.h
:
ENET_PEER_TIMEOUT_LIMIT = 32, ENET_PEER_TIMEOUT_MINIMUM = 5000, ENET_PEER_TIMEOUT_MAXIMUM = 30000,
The documentation doesn't have too much information. The code can be obtained from http://enet.bespin.org/Downloads.html.
In peer.c
you can find the following method to change the timeout settings for each peer:
/** Sets the timeout parameters for a peer. The timeout parameter control how and when a peer will timeout from a failure to acknowledge reliable traffic. Timeout values use an exponential backoff mechanism, where if a reliable packet is not acknowledge within some multiple of the average RTT plus a variance tolerance, the timeout will be doubled until it reaches a set limit. If the timeout is thus at this limit and reliable packets have been sent but not acknowledged within a certain minimum time period, the peer will be disconnected. Alternatively, if reliable packets have been sent but not acknowledged for a certain maximum time period, the peer will be disconnected regardless of the current timeout limit value. @param peer the peer to adjust @param timeoutLimit the timeout limit; defaults to ENET_PEER_TIMEOUT_LIMIT if 0 @param timeoutMinimum the timeout minimum; defaults to ENET_PEER_TIMEOUT_MINIMUM if 0 @param timeoutMaximum the timeout maximum; defaults to ENET_PEER_TIMEOUT_MAXIMUM if 0 */
Therefore timeouts can be changed in NetServer.cpp
in the function CNetServerWorker::RunStep
, for the case ENET_EVENT_TYPE_CONNECT
by adding for example:
enet_peer_timeout(event.peer, 0, 0, 10000);
The timeout logic can be found in protocol.c
.
If I understand the matter correctly, the client will be disconnected after 5 seconds if he had good latency before disconnecting. If he already had bad latency then enet will wait up to 30 seconds.