【问题标题】:TcpClient/NetworkStream not detecting disconnectionTcpClient/NetworkStream 未检测到断开连接
【发布时间】:2015-07-13 00:23:22
【问题描述】:

我使用TcpClientNetworkStream 为我们的游戏创建了一个简单的持久套接字连接。正常连接、发送消息和断开连接没有问题(退出应用/服务器关闭/等)。

但是,我遇到了一些问题,在某些情况下,客户端没有检测到与服务器的断开连接。我最简单的测试方法是拔掉 wifi 盒子上的网线,或者将手机设置为飞行模式,但它发生在游戏中间,本来应该是稳定的 wifi。

浏览NetworkStream 等的文档,它说检测断开连接的唯一方法是尝试写入套接字。很公平,除了,当我尝试时,写入通过了,好像没有任何问题。我可以像这样写多条消息,一切似乎都很好。只有当我重新插入电缆时,它才会看到它已断开连接(所有消息都被缓冲了?)。

TcpClient 设置为 NoDelay,并且在每次写入之后都会调用 Flush()

我尝试过的:

  • NetworkStream 写消息 - 不开心
  • CanWriteConnected等都返回true
  • TcpClient.Client.Poll( 1000, SelectMode.SelectWrite ); - 返回真
  • TcpClient.Client.Poll( 1000, SelectMode.SelectRead ) && TcpClient.Client.Available == 0 - 返回真
  • TcpClient.Client.Receive(buffer, SocketFlags.Peek) == 0 - 连接后,阻塞大约 10-20 秒,然后返回 true。当没有服务器时,永远阻塞(?)
  • NetworkStream.Write() - 不会抛出错误
  • NetworkStream.BeginWrite() - 不会抛出错误(即使在调用 EndWrite() 时也不会)
  • 设置WriteTimeout - 无效
  • 有一个特定的时间我们没有收到来自服务器的消息(通常有一个保持活动状态) - 我有这个,但删除了它,因为由于滞后等原因我们得到了很多误报(有些客户会看到 10-20 秒的延迟)

那么我在这里做错了吗?在写入应该断开的套接字时,有什么方法可以让NetworkStream 抛出错误(应该如此)?

我对keep-alive没有问题(默认情况是服务器会通知客户端它有一段时间没有收到任何东西,客户端会发送心跳),但在这一分钟,根据到NetworkStream 一切都很好。

这是针对游戏的,所以理想情况下检测应该足够快(因为用户仍然可以在游戏中移动,直到他们需要进行服务器调用,其中一些会阻塞 UI,所以游戏似乎坏了)。

我使用的是 Unity,所以它是 .Net 2.0

【问题讨论】:

    标签: tcp unity3d tcpclient networkstream


    【解决方案1】:

    就是拔掉wifi盒子上的网线

    这是一个很好的测试。如果您这样做,则不会通知远程方。它怎么可能发现?不能。

    当我尝试时,写入通过,好像没有任何问题

    写入可以(并且被)缓冲。他们最终进入了一个堵洞……没有回复回来。检测到这一点的唯一方法是超时。

    所以我在这里做错了吗?

    您已经尝试了很多事情,但如果没有回复告诉您,从根本上说您无法发现断开连接。使用超时。

    【讨论】:

    • 谢谢 - 拔出网络电缆是我唯一可以测试的方法 - 实际错误发生在生产代码中,而用户应该连接到稳定的 wifi。超时,你的意思是在客户端,如果他们在 X 时间内没有收到消息,对吧?
    • "stable wifi" 我从来没有见过这样的事情 :) 没关系,这个问题可能由于多种原因而发生。你必须能够处理它。关于超时:它必须在想要检测连接丢失的一侧。似乎很明显......我理解你的问题了吗?
    • 好的,我想我明白了 - 写入正在缓冲,所以对于客户端来说,一切都很好。而且,是的,超时 - 我只是习惯于人们谈论服务器端超时,所以我想澄清一下
    • 我接受答案之前的最后一个问题:有没有办法为套接字设置最大“缓冲”时间。 IE。如果它被缓冲了 X 秒而没有被发送,那么断开连接?这会被自定义客户端超时覆盖吗?
    • Nagling 是导致发送主机上大部分缓冲的原因。也许您可以更改 nagling 时间(默认值:200 毫秒)。这无济于事,因为数据成功发送。只是没有收到。 TCP 堆栈在这里不能做太多事情。无论堆栈实现超时还是您的代码实现它原则上都不会改变任何东西。 TCP 堆栈唯一能做的就是执行重传,但这不会救你。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-12-04
    • 1970-01-01
    • 1970-01-01
    • 2016-08-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多