Real-time Detection of Client Disconnection from Server Socket

Dec 02, 2025 · Programming · 10 views · 7.8

Keywords: Socket connection detection | TCP disconnection monitoring | .NET network programming

Abstract: This paper explores the mechanisms for real-time detection of TCP Socket client disconnections in .NET C# server applications. Focusing on asynchronous Socket programming models, it presents a reliable detection method based on the Poll approach with complete code implementations. The study also compares alternative solutions like TCP Keep-Alive, explaining their working principles and application scenarios, providing systematic solutions for connection state management in network programming.

Introduction

In network programming, real-time detection of client connection status is a common yet critical requirement for server applications. Particularly in asynchronous Socket programming models, where no built-in event mechanism notifies disconnections, developers must implement active detection logic. This paper analyzes several detection methods based on practical development challenges.

Problem Context

In typical asynchronous Socket server implementations, after a client connection is established via the AcceptCallback method, the server maintains a Socket object for communication. However, when clients disconnect abnormally (e.g., network failure, program crash), the server often cannot immediately detect this, potentially leading to resource leaks or business logic errors.

Common attempts include checking the Socket.Available property or attempting to send/receive data, but these methods are often unreliable for server-side client disconnection detection. For instance, calling handler.Send or handler.Receive may block or throw exceptions but does not provide real-time, proactive detection capabilities.

Core Solution: Poll Method Detection

The most reliable solution involves using the Socket.Poll method combined with the Available property for state detection. This method polls the Socket's status to determine connection validity, with the core principle as follows:

public static bool IsConnected(this Socket socket)
{
    try
    {
        return !(socket.Poll(1, SelectMode.SelectRead) && socket.Available == 0);
    }
    catch (SocketException) { return false; }
}

This extension method works by:

  1. socket.Poll(1, SelectMode.SelectRead) checks if the Socket is readable within a 1-microsecond timeout
  2. If the Socket is readable but Available == 0, the connection is closed
  3. Any SocketException is treated as a disconnection

In practice, servers can call this method periodically in a separate thread or timer:

// Periodic connection state detection
while (isRunning)
{
    if (!handler.IsConnected())
    {
        // Handle disconnection logic
        handler.Close();
        break;
    }
    Thread.Sleep(pollInterval);
}

Advantages of this approach include:

Alternative Approach: TCP Keep-Alive Mechanism

Beyond active polling, the TCP protocol itself provides a Keep-Alive mechanism as another detection option. By setting Socket options, the operating system can automatically send heartbeat packets to maintain connection liveliness:

void SetKeepAlive(bool on, uint keepAliveTime, uint keepAliveInterval)
{
    int size = Marshal.SizeOf(new uint());
    var inOptionValues = new byte[size * 3];
    
    BitConverter.GetBytes((uint)(on ? 1 : 0)).CopyTo(inOptionValues, 0);
    BitConverter.GetBytes((uint)keepAliveTime).CopyTo(inOptionValues, size);
    BitConverter.GetBytes((uint)keepAliveInterval).CopyTo(inOptionValues, size * 2);
    
    socket.IOControl(IOControlCode.KeepAliveValues, inOptionValues, null);
}

The Keep-Alive mechanism operates as follows:

  1. Sends the first heartbeat packet after keepAliveTime milliseconds of no data exchange
  2. Retries every keepAliveInterval milliseconds if no acknowledgment is received
  3. After multiple failures, the connection is marked as disconnected

In asynchronous receive callbacks, disconnections can be detected by catching SocketException:

public void OnDataReceived(IAsyncResult asyn)
{
    try
    {
        SocketPacket theSockId = (SocketPacket)asyn.AsyncState;
        int iRx = socket.EndReceive(asyn);
    }
    catch (SocketException ex)
    {
        // Handle disconnection
        SocketExceptionCaught(ex);
    }
}

Solution Comparison and Selection Guidelines

Both approaches have distinct advantages and disadvantages:

<table border="1"><tr><th>Approach</th><th>Advantages</th><th>Disadvantages</th><th>Use Cases</th></tr><tr><td>Poll Polling</td><td>Real-time control, simple implementation, OS-independent</td><td>Requires additional thread, consumes CPU resources</td><td>Real-time systems requiring quick response</td></tr><tr><td>TCP Keep-Alive</td><td>OS-level support, low resource consumption</td><td>Complex configuration, higher response latency</td><td>Long-lived connections, resource-constrained environments</td></tr>

Selection recommendations:

Best Practices and Considerations

In practical development, the following points are essential:

  1. Exception Handling: All Socket operations should include comprehensive exception handling, particularly for SocketException
  2. Resource Management: Promptly release Socket resources upon disconnection detection to prevent memory leaks
  3. Performance Optimization: Adjust Poll intervals based on actual requirements to avoid performance impacts from excessive detection
  4. Thread Safety: Ensure synchronization when accessing Socket objects in multi-threaded environments
  5. Logging: Record disconnection times and reasons for troubleshooting

A complete implementation example:

public class ConnectionMonitor
{
    private Socket _socket;
    private Thread _monitorThread;
    private volatile bool _isMonitoring;
    
    public void StartMonitoring(Socket socket, int intervalMs = 1000)
    {
        _socket = socket;
        _isMonitoring = true;
        _monitorThread = new Thread(() =
        {
            while (_isMonitoring && _socket != null)
            {
                if (!_socket.IsConnected())
                {
                    OnDisconnected();
                    break;
                }
                Thread.Sleep(intervalMs);
            }
        });
        _monitorThread.Start();
    }
    
    private void OnDisconnected()
    {
        // Clean up resources
        _socket?.Close();
        _socket = null;
        _isMonitoring = false;
        
        // Notify business layer
        Console.WriteLine($"Client disconnected at {DateTime.Now}");
    }
}

Conclusion

Detecting client Socket disconnections on the server side is a crucial functionality requiring careful design. The polling approach based on Socket.Poll provides reliable, real-time detection capabilities, while the TCP Keep-Alive mechanism offers OS-level support. Developers should choose appropriate solutions based on specific application scenarios or combine both for enhanced effectiveness. Regardless of the chosen approach, robust exception handling, resource management, and logging remain key factors in ensuring system stability.

Copyright Notice: All rights in this article are reserved by the operators of DevGex. Reasonable sharing and citation are welcome; any reproduction, excerpting, or re-publication without prior permission is prohibited.