【问题标题】:Client usually disconnected from server after a few dozen minutes客户端通常在几十分钟后与服务器断开连接
【发布时间】:2014-05-23 07:49:16
【问题描述】:

我在 .NET(c# 或 vb.net)中创建了一个服务器-客户端通信程序,使用 TCPListener - 端口 8080 上的套接字。简而言之,该程序像聊天软件一样工作,客户端连接到服务器,两者兼而有之等待对方的消息,然后处理它。

为了从客户端检索数据包,我使用的是这样的“While”方法:

While true

Dim Buffer(4096) As Byte

s.Receive(Buffer)

Dim strDataReceived As String = System.Text.Encoding.ASCII.GetString(Buffer)

ProcessData(strDataReceived) 'Process data received...........

End while

在本地测试 server.exe-client.exe 时,软件可以正常运行几个小时,没有任何问题。

但是当我开始在我的真实服务器上运行 server.exe 时,服务器-客户端之间的连接通常会在客户端连接数十分钟后相互丢失。症状是客户端向服务器发送数据包,但当服务器仍处于“sck.receive(Buffer)”命令时,服务器没有收到来自客户端的数据包。我已经测试了很多次,但我仍然没有幸运地保持连接运行超过 1 小时。

我已经调查过这个问题,但仍然很奇怪:

  • 服务器未安装任何防火墙软件。

  • 客户端没有使用任何代理和杀毒、防火墙软件

  • 我在服务器上使用带宽记录软件来确保我的服务器中的互联网是稳定的。

  • 我从客户端计算机向服务器发出“ping -t”,并继续查看它以确保客户端和服务器之间没有丢失连接。 ping命令表示ping时间一般在5ms到50ms之间,不会出现连接超时。

  • 我什至尝试在客户端计算机中拔下网线几秒钟,然后再次重新插入以模拟断开连接事件。我很高兴我的服务器-客户端之间的连接仍然保持不变,这不是导致我出现症状的问题。

如果收到超时,我正在考虑编写自动重新连接的代码。但是如果上述症状仍然存在,它可能会使我的软件在重新连接时通常会延迟。我真的很想知道我的代码有什么问题,解决上述症状的方法是什么?

【问题讨论】:

  • 我不知道为什么它会中断一个真实的、实时的连接(可能是关于套接字空闲和关闭的一些事情),也许比我更了解 TCP 的人可以回答这个问题。但是,您真的想长时间保持连接空闲吗?在我见过的大多数实现中,想要让套接字长时间保持打开而不接收数据的软件会每隔一段时间发送一个保持活动数据包以确保套接字保持活动状态。哦,请确保您 a) 刷新流(如果它被缓冲)并且 b) 没有达到 nagle 效果
  • 我发现通常是 ISP 断开了长时间运行的 TCP 连接。如果我是 OP,我会编写服务器以侦听传入连接而无需使用 while 循环。当客户端发送消息时,它会执行“连接 - 发送 - 断开连接”来发送消息。读取消息可以是不同的例程,其中客户端也设置为侦听而不是 while 循环。当客户端第一次连接时,即使断开连接,服务器也会将其保持为“这是一个打开的连接”,以便知道在有消息时向客户端发送消息。
  • 我同意keealive数据包。但在谈论几十分钟时,他并没有达到 nagle 算法。那个算法不是那样工作的。缓冲/延迟在 TCP 堆栈内完成,并且在高传输率下也相关,而不是几分钟。堆栈将在几毫秒内自行刷新数据包。如果设置正确,您不必刷新 TCP 套接字。实际上,您无法在大多数操作系统上刷新它。也许通过切换 TCP_NODELAY,正如我在 Linux 上所读到的那样。如果有的话,nagle 只会损害性能。
  • 我不确定 nagle 算法在这里是否相关 - 这更多地与组合短数据包以减少数据包头的开销有关。更有可能只是连接超时,因为没有任何流量。
  • 是的,我为错误信息道歉。 Nagle 仅在您进行写入写入读取时在短时间内起作用。

标签: c# .net vb.net sockets


【解决方案1】:

服务器可能位于具有空闲连接超时的某种防火墙(Cisco ASA 等)后面。当您“穿透”防火墙/NAT 设备时,会在防火墙内核中创建一个“会话”。有一个关联的资源需要回收,因此防火墙通常不允许无限连接超时,但防火墙确实支持死连接检测等功能。

每 5 分钟添加一个 keepalive 数据包/活动,或者断开/重新连接是解决此问题的唯一方法。很少有网络管理员会更改他们的配置以适应这种情况。在自定义 TCP 应用程序协议中实现“ping”或“keepalive”命令非常简单。只需发送字符串并使用它,您甚至不必响应数据包即可完成防火墙内的空闲计时器重置,尽管这可能是最佳实践。

当我说 keepalive 时,我并不是指 TCP keepalive 套接字选项。这是一个长度为零的数据包,可以被良好的防火墙(如 Cisco)检测到。 Cisco 管理员可以设置规则来悄悄拒绝您的 keepalive 数据包,因此解决方案是在 TCP 层之上的应用程序中实现它层,通过发送一小串数据,如“KEEPALIVE\r\n”。

【讨论】:

  • 正如我所提到的,我没有在服务器中安装任何防火墙。自从安装了Window以来,服务器中的所有软件都是由我设置的,所以我知道没有安装防火墙。
  • 那么你的客户端和服务器在同一个物理网络上?我没有说“服务器”有防火墙。我的意思是防火墙在客户端和服务器之间。除非它们在同一个网络上,否则您可能正在通过防火墙并且不知道它。
  • 客户端也是我的家用电脑(也使用我的家庭网络),所以我知道上面没有防火墙。我还在我的电脑上运行了其他软件,比如雅虎、Skype,这些都是长连接软件,而且它仍然非常稳定。
  • 服务器在数据中心运行
  • 这是我的观点。你自己已经说过了:“但是当我开始在我的真实服务器上运行 server.exe 时,服务器-客户端之间的连接通常会丢失”
猜你喜欢
  • 2019-07-06
  • 2020-05-06
  • 1970-01-01
  • 1970-01-01
  • 2015-05-17
  • 2020-02-13
  • 2013-03-31
  • 2020-05-26
  • 1970-01-01
相关资源
最近更新 更多