我有两个应用程序 第一个打开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 上的两个应用程序
默认情况下,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 更容易实现。