When the other side vanishes without a close signal, TCP notices only much later. Keepalive (a TCP feature that checks whether an idle connection is still alive) is off by default, and even when it’s on, checks start only after 2 hours of idle time.
Why The client vanishes without a close signal because its power went off or its connection dropped → Effect The server assumes the connection is still alive (keepalive default 7,200 s; if data was being sent, about 15 minutes until retransmission gives up) → On screen A ghost character stays behind, and reconnecting fails with an “Already logged in” error
After sitting idle, Right after login or maintenance
Owner
Primary owner Game team (Server development) · Also Game team (Client development), Infra team (Server infrastructure)
Game team action items
Server: answer heartbeats and close the connection yourself if nothing arrives for a set time (tune TCP_KEEPIDLE and TCP_USER_TIMEOUT), and on reconnect use the session token to replace the old session and resume it. Client: send game-level heartbeats every few seconds to tens of seconds (half the shortest idle timeout or less), reconnect automatically when disconnected.
Infra team action items
Lower the kernel defaults (tcp_keepalive_time and so on) for sockets whose code doesn’t set its own values (applies only to sockets with SO_KEEPALIVE on).
Ballpark numbers
By default, Linux starts checking after 7,200 seconds of idle time, sends 9 probes 75 seconds apart, and drops the connection if none are answered. That adds up to about 2 hours 11 minutes. Windows also waits for 2 hours of idle time by default before it starts checking.
On the graph
Outliers only · Time since last receive, per connection
Where to look
lastrcv (ms since the last receive) and the keepalive timer (timer:(keepalive,…)) per connection from ss -tnoi, lined up with the game server’s “Already logged in” rejections
Confirmed if
ESTABLISHED connections with lastrcv of minutes to hours are still there, and reconnects for those accounts are rejected with “Already logged in”
Ruled out if
No long-silent connections, yet “Already logged in” still appears: the game server’s session cleanup code
Check with
Infra tools (no game code needed)
Sources
tcp(7) — Linux manual pageLinux man-pages 9 probes 75 s apart after 7,200 s of idle time (about 11 more minutes), applies only to sockets with SO_KEEPALIVE on, TCP_KEEPIDLE and TCP_USER_TIMEOUT