为 SocketOptionLevel.Socket 设置后没有 KeepAlive 请求

问题描述 投票:0回答:1

我有两个应用程序 第一个打开TcpClient:

 client = new TcpClient();
 client.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.KeepAlive, true);
 client.NoDelay = true;
 client.Connect(settings.Hostname, settings.Port);

第二个听:

        var listener = new TcpListener(settings.IPAddress, settings.Port);

        var listenerThread = new Thread(() => Listen(listener, cancellationTokenSource.Token))
        {
            IsBackground = true,
            Priority = ThreadPriority.AboveNormal,
        };

       private void Listen(TcpListener tcpListener, CancellationToken cancellationToken)
       {
        tcpListener.Start();

        // stop listener on cancellation
        cancellationToken.Register(tcpListener.Stop);

        try
        {
            while (!cancellationToken.IsCancellationRequested)
            {
                var client = tcpListener.AcceptTcpClient();
                client.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.KeepAlive, true);

                // Register client in background
                Task.Run(() => RegisterClientConnection(client), cancellationToken)
                    .LogErrors(SystemLogManager.Current, "Error while registering client connection");
            }
        }
        catch (SocketException)
        {
            // logging
        }
    }

以及一些读取流的逻辑:

using (var clientStream = tcpClient.GetStream())
...
bytesRead = await clientStream.ReadAsync(messageBuffer, messageBufferPointer, tcpClient.ReceiveBufferSize, cancellationToken);

奇怪的是,我在wireshark中没有看到任何保持活动的请求,并且连接在5分钟后被天蓝色防火墙断开。 为什么“保持活动”在我的情况下不起作用?

.netframework 4.7.2 上的两个应用程序

c# tcpclient keep-alive
1个回答
0
投票

默认情况下,TCP keepalive 每 2 小时发送一次,因此它们不会在不到 5 分钟内出现。

如果您使用的是 Win 10 (1709) 或更高版本,您可以通过 设置

TCP_KEEPIDLE
TCP_KEEPINTVL
套接字选项
来调整此时间;更通用的解决方案(Windows 2000+)是 向套接字句柄发送
SIO_KEEPALIVE_VALS
IOCTL

但是,请注意 TCP keepalive 是 TCP 规范的“可选”部分。路由器和软件网络可能会忽略 TCP keepalive。 Windows 支持 TCP keepalive,但我不确定您使用的 Azure 组件是否支持 TCP keepalive。 由于您控制软件的双方,

我建议在应用程序协议级别创建保活消息

(如我的博客中所述)。通过发送空消息可以相对轻松地完成此操作;例如,如果您使用长度前缀消息帧,则只需发送长度前缀 0。使用应用程序级保活会强制所有中间路由器传送它(因为它是应用程序数据),并且同样简单(如果不是)比 TCP 级别的 keepalive 更容易实现。

© www.soinside.com 2019 - 2024. All rights reserved.