关于 c#:Detecting drop connections

Detecting dropped connections

我有一台服务器和许多客户端。服务器需要知道客户端何时非正常断开连接(不发送 TCP FIN),以便它没有与该客户端关联的挂起连接和其他一次性对象。

无论如何,我读了这篇文章并决定从链接的博客中添加一个"keepalive 消息到应用程序协议"(仅包含头字节)和"假设最坏的显式计时器"方法。

当客户端连接时(顺便说一句,我正在使用 TcpListener 和 TcpClient),服务器启动一个 System.Threading.Timer 倒计时 30 秒。每当服务器从该客户端接收到某些内容时,它都会重置计时器。当计时器达到 0 时,它会断开用户并处理它需要处理的任何内容。客户端应用程序也有一个计时器,当用户在 15 秒内(服务器值的一半,只是为了确定)没有发送任何内容时,它会发送 keepalive 消息。

我的问题是,有没有更简单的方法来实现这一点?也许 TcpClient 上有一些选项?我尝试使用 TcpClient.ReceiveTimeout,但这似乎不适用于 ReadAsync。


正如 Stephen 指出的那样,在应用程序协议中使用心跳消息是确保连接处于活动状态并且两个应用程序都正常运行的唯一可靠方法。请注意,许多工程师已经创建了一个心跳线程,即使应用程序线程发生故障,它也会继续运行。

使用这里的类将解决您的异步套接字问题。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
public sealed class SocketAwaitable : INotifyCompletion
{
    private readonly static Action SENTINEL = () => { };

    internal bool m_wasCompleted;
    internal Action m_continuation;
    internal SocketAsyncEventArgs m_eventArgs;

    public SocketAwaitable(SocketAsyncEventArgs eventArgs)
    {
        if (eventArgs == null) throw new ArgumentNullException("eventArgs");
        m_eventArgs = eventArgs;
        eventArgs.Completed += delegate
        {
            var prev = m_continuation ?? Interlocked.CompareExchange(
                ref m_continuation, SENTINEL, null);
            if (prev != null) prev();
        };
    }

    internal void Reset()
    {
        m_wasCompleted = false;
        m_continuation = null;
    }

    public SocketAwaitable GetAwaiter() { return this; }

    public bool IsCompleted { get { return m_wasCompleted; } }

    public void OnCompleted(Action continuation)
    {
        if (m_continuation == SENTINEL ||
            Interlocked.CompareExchange(
                ref m_continuation, continuation, null) == SENTINEL)
        {
            Task.Run(continuation);
        }
    }

    public void GetResult()
    {
        if (m_eventArgs.SocketError != SocketError.Success)
            throw new SocketException((int)m_eventArgs.SocketError);
    }
}