【发布时间】:2011-02-01 02:32:08
【问题描述】:
我在基于 TCP 的客户端软件中遇到了一个有趣/烦人的情况,它是这样的:
- 我的客户端进程在笔记本电脑上运行,它通过 TCP 连接到我的服务器进程(通过 LAN 在另一台机器上运行)
- 不负责任的用户在客户端传输 TCP 数据时将以太网电缆从笔记本电脑中拔出
- 客户端进程继续使用一些额外的 TCP 数据调用 send(),填满操作系统的 SO_SNDBUF 缓冲区,直到...
- (通过 MacOS/X 的 SCDynamicStoreCallback 功能)通知客户端进程以太网接口已关闭,并通过调用其 TCP 套接字上的 close() 来响应
- 两到五秒过去了...
- 用户重新插入以太网电缆
- 通知客户端进程接口已备份,并自动重新连接到服务器
这一切都很好......除了通常还有一个不需要的步骤 8,即:
.8。在第 4 步中关闭()的 TCP 套接字恢复(!)并发送该套接字的内核出站数据缓冲区中的剩余数据。发生这种情况是因为操作系统会在释放套接字之前尝试传递所有出站 TCP 数据……通常是一件好事,但在这种情况下,我宁愿不要发生这种情况。
那么,问题是,有没有办法告诉 TCP 层将数据丢弃在其 SO_SNDBUF 中?如果是这样,我可以在步骤 4 中关闭()死套接字之前进行该调用,并且我不必担心在旧套接字被废弃后来自旧套接字的僵尸数据到达服务器。
【问题讨论】:
-
在我看来,这听起来像是 Apple 实施中的一个错误。您可以将套接字的 SO_LINGER 设置为 0,这将消除调用 close 和实际发生 close 之间的等待。在
close成功后,不应再传输数据。 unix.org/single_unix_specification_v3 -
@Jerry Coffin:不应接受通过
send()调用传输的数据,但仍应传输先前写入的数据。 -
@caf:SUS 似乎不同意:“如果 fildes 指的是套接字,则 close() 将导致套接字被销毁。如果套接字处于连接模式,并且 SO_LINGER为具有非零延迟时间的套接字设置了选项,并且套接字具有未传输的数据,则 close() 将阻塞当前的延迟时间,直到传输所有数据。逗留时间到期后,套接字被销毁 - 期间。没有更多数据被接受或传输。
-
@Jerry Coffin:并不是说套接字立即被销毁。如果
SO_LINGER没有设置,那只是意味着close()不会阻塞。 POSIX 更清楚地说明了这一点 - “如果未指定 SO_LINGER,并且发出了 close(),系统会以允许调用线程尽快继续的方式处理调用。”。