gpt4 book ai didi

c - 客户端不可预测的异常关闭

转载 作者:可可西里 更新时间:2023-11-01 02:51:42 27 4
gpt4 key购买 nike

我正在使用一个相当基本的服务器/客户端设置,它们都位于同一网络上。他们通过 TCP/IP 上的 Winsock2 blocking 套接字进行通信,并且运行得非常好。

但是,对于下面描述的场景,客户端有时会看到连接终止 (RST) 失败。它在 100 次中大约有 99 次是正确的,但最后一次令人讨厌地失败了一些测试,因此,我的整个构建。它发生的时间和地点是完全不可预测的,所以到目前为止我还没有重现这个问题。

如果我理解the relevant MSDN page正确地,阻塞套接字的标称连接终止顺序可以概括为:

Client               |  Server
-----------------------------
shutdown(SD_SEND) |
| send() response data
i=recv() until i==0 | shutdown(SD_SEND)
closesocket() | closesocket()

在我的设置中有必要

  1. 根据接收数据的一部分(比方说,512 字节)是否包含触发值,执行相对昂贵的操作(我们称之为 expensive_operation())。服务器是单线程的,因此 expensive_operation() 有效地停止了 recv() 数据流,直到 expensive_operation() 完成
  2. 如果客户端发送特定的标记值,则启动服务器关闭序列,我们称其为 0xDEADBEEF

我的客户端是这样实现的,标记值总是最后发送,所以在发送之后,没有其他数据被发送:

  1. 发送(“数据数据数据0xDEADBEEF”)到服务器
  2. shutdown(SD_SEND) <-------- 此处发生故障
  3. recv() 直到接收到 0 个字节
  4. closesocket()

每当服务器收到0xDEADBEEF,它确认关闭请求并继续终止:

  1. recv() 512 字节数据或直到返回 0 字节
  2. 检查触发器。如果找到触发器,则执行expensive_operation()并返回步骤1,否则继续
  3. 检查标记值。如果没有找到 sentinel,则返回步骤 1。
  4. 如果找到哨兵:
    1. 发送(确认)给客户端
    2. 关机(SD_SEND)
    3. closesocket()
    4. 所有正常的服务器关闭内容

我可以理解,如果客户端打算在哨兵之后发送更多 数据,这将导致连接终止——因为服务器主动终止连接。这是完全预期的设计,我确实可以可靠地重现此行为。

然而,在名义上的情况下,哨兵总是在序列中最后,这确实总是发生,相关日志条目证明了这一点,并且确实是优雅的连接终止大部分时间都按预期发生。但是并不总是...

正如我所说,它是随机和偶尔发生的,所以我无法生成可靠地重现该问题的代码片段。唯一一致的是,在客户端调用 shutdown() 时总是失败...

我怀疑这更多是设计缺陷,或者是我尚未处理的同步问题,而不是代码问题(尽管我很乐意提供相关代码片段)。

那么我在这里忽略了什么明显的东西吗?

最佳答案

除了在发送端故意这样做之外,您可以通过多种方式激发 RST 的发送,我不会在这里透露:

  1. 写入一个已经被对方关闭的连接。尝试几次后,这将导致 ECONNRESET。
  2. 在未读取所有已挂起数据的情况下关闭连接。这将导致立即 ECONNRESET。

这两个都表示应用程序协议(protocol)错误。

在你的情况下,我会摆脱哨兵。这是多余的。只需关闭用于输出的套接字,或者如果您知道没有更多数据传入则关闭它。这会向对等方发送一个完全明确的指示,表明没有更多数据,而无需对对等方进行精确同步字节-byte 与本地应用程序,这是您当前代码中此错误的弱点和可能来源。

您需要发布一些代码以获得更具体的帮助。

关于c - 客户端不可预测的异常关闭,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29963619/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com