linux - 同时 TCP 终止和后续 connect() : EADDRNOTAVAIL

标签 linux sockets networking tcp

我的公司发布了一个用于特殊用途的特殊 TCP 堆栈,我的任务是实现符合 RFC793 的关闭序列。其中一个单元测试有一个服务器在特殊的 TCP 堆栈之上工作,与一个普通的 Linux TCP 客户端通信,我遇到了一些奇怪的行为,我不确定是我的编程错误引起的还是意料之中。

在我开始工作之前,我们曾经在用户应用程序调用 close() 时发送一个 RST 数据包。我已经实现了 FIN 握手,但我注意到在同时 TCP 终止的情况下(FIN_WAIT_1 -> CLOSING -> TIME_WAIT 在两端,见图),标准 Linux TCP 客户端无法连接到相同的目标地址和端口再次,connect() 返回 EADDRNOTAVAIL,直到 TIME_WAIT 进入 CLOSED。

simultaneous close

现在,标准的 Linux 客户端应用程序设置选项 SO_REUSEADDR,每次都将套接字绑定(bind)到端口 8888,并连接到目标端口 6666。我的问题是,为什么 bind() 成功,为什么connect() 失败了吗?我原以为 SO_REUSEADDR 可以接管本地 TIME_WAIT 端口,它确实这样做了,但是 connect() 有什么反对再次与目标 ip:6666 交谈?

我的代码是在做一些不应该做的事情还是这是预期的行为?

我可以确认失败的 connect() 根本没有 SYN 数据包从客户端计算机发出。我附上了上述 session 的 FIN 握手截图。

enter image description here

最佳答案

您之前的实现使用了 RST结束连接。收据 RST数据包立即从事件连接表中删除连接。那是因为在该连接上没有进一步接收有效数据包的可能性:对等方刚刚告诉您的系统该 session 无效。

如果您使用 FIN 正确终止 session ,另一方面,还有最后一个数据包问题:您如何确定对等方是否确实收到了您发送给他们的 FIN 的最后一个确认。 (这是TCP的TIME_WAIT状态的定义)?如果对等方没有收到它,他们可能会有效地发送 FIN 的另一个副本。然后您的机器应该重新发送的数据包 ACK .

现在,您的 bind成功是因为您使用的是 SO_REUSEADDR , 但您仍然无法使用两侧完全相同的端口 创建新连接,因为该条目仍在您的事件连接表中(处于 TIME_WAIT 状态)。 4 元组(IP1、端口 1、IP2、端口 2)必须始终是唯一的。

正如@EJP 在评论中建议的那样,客户端指定端口是不常见的,而且通常没有理由这样做。我会改变你的测试。

关于linux - 同时 TCP 终止和后续 connect() : EADDRNOTAVAIL,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51417495/

相关文章:

C 发送数据后断开连接

c++ - 解析/etc/network/interfaces

android - 我应该为 GPS 和网络提供商使用单独的 locationManager 吗?

linux - 如何调整内核模块以通过 `no symbol version for module_layout` ?

c - bash 使用什么来打开/执行 argv[0]?

json - kubernetes 服务未启动

sockets - 使用 boost::asio async_read_some 的高 CPU 和内存消耗

java - 从单独的方法中引用套接字

linux - 如何回复linux提示(根据提示中的关键字)

互联网上的 iOS Bonjour