测试关闭的套接字

10

我试图测试由对等方优雅地关闭的已关闭套接字,而不会产生双重发送以引发 SIGPIPE 的延迟损失。

这里的假设之一是,套接字如果关闭,则是在其最后的写入/发送后立即被对等方优雅地关闭的。实际的错误,例如过早关闭,在代码的其他位置处理。

如果套接字仍然打开,将有0或更多字节的数据,我实际上不想从套接字缓冲区中提取这些数据。

我想到可以调用 int ret = recv(sockfd, buf, 1, MSG_DONTWAIT | MSG_PEEK); 来确定套接字是否仍连接着。如果它仍然连接,但缓冲区中没有数据,我将得到 -1 的返回值,并且 errno == EAGAIN,并返回 sockfd 以供重复使用。如果它已经被对等方优雅地关闭,则我将得到 ret == 0 并打开一个新连接。

我已经测试过这个方法,看起来是有效的。但是,我怀疑在我接收到最后一位数据和对等方发送 FIN 之间可能存在一个很小的时间窗口,在这个时间窗口内我的测试 recv 可能会出现错误的 EAGAIN

这会对我产生影响吗?还是有更好的方法可以做到这一点?


一种替代方法是使用 select()(或 poll()),因为它可以控制 fd 既读又写,但我不知道它是否真正解决了您关于 FIN 时间的问题。 - Giuseppe Guerrini
@Giuseppe:不,我认为select不能解决时间问题。 - Robert S. Barnes
3个回答

3

好的,我进行了更多测试,这是我的发现。

我设置了客户端发送 HTTP/1.1 Connection: close 消息到服务器,导致服务器在最后一次写入数据后调用关闭。当我的客户端完成从 GET 事务中读取数据后,它会使用上述方法测试套接字是否仍然打开,然后尝试发出另一个 GET。

我发现大约有30%的时间,我的测试会在服务器的 FIN 到达之前发生,导致误报和操作失败。

可能唯一使此工具相对可靠的方法,例如接近99%,就是引入与最后一次读取和尝试套接字重用之间的连接延迟相关的人为延迟-但是,这几乎会导致性能下降。

因此,我必须得出结论,虽然这个工具很有用,但只是略微有用。


1
+1:有趣的测试。人们可以理解为什么在电信领域90%的代码用于管理异常行为 :) - neuro

0
你控制另一端吗?执行套接字的“干净”关闭最可靠的方法是让另一端发送某种“再见”消息。

1
不,我不能控制另一端。然而,另一端应该始终发送一个应用程序级别的消息,表明他们正在关闭连接。只是在现实世界中,这并不总是发生。我可以像处理常规错误一样处理它,但大多数情况下我想尝试主动捕获它。 - Robert S. Barnes

0
(略微“离题”,抱歉)。也许this discussion对你有所帮助。它仍然没有回答你的“FIN”问题,但可以帮助你更轻松地应对同行关闭连接而你的程序正在发送数据的情况。
再见

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接