在Steven的“The Socket:Networking API,Third Edition”的第4章第4.3节中,作者陈述如下
"If connect fails, the socket is no longer usable and must be closed. We cannot call connect again on the socket."
有没有人知道上述说法背后的原因?
在我自己的实验中,我编写了一个简单的tcp客户端,它将运行在主机A和一个简单的tcp服务器上,运行在主机B上。tcp客户端将尝试连接到主机B上的tcp服务器。
所以,我启动了主机B上的服务器。从主机拉出networking线。 然后我启动了主机A上的客户端。在同一个套接字上连接大约9次连接失败后,我只需将networking连接线插回服务器主机。 客户端连接成功,并愉快地以80K /秒发送消息。
在另一个实验中,我从服务器主机上取下了电线,初次成功连接之后,几百万条信息交换完毕。 然后,几分钟后,我连接线和消息stream恢复在同一个套接字。
POSIX 2001在信息部分说 :
如果
connect()
失败,那么套接字的状态是未指定的。 符合的应用程序应该关闭文件描述符并在尝试重新连接之前创建一个新的套接字。
所以你引用的段落与这个规范是一致的。 它在你的机器上工作的事实并不意味着你的程序是可移植的。
这可能植根于连接的手册 ,它说:
通常,基于连接的协议套接字只能成功
connect()
一次; 无连接协议套接字可以多次使用connect()
来改变它们的关联。
这意味着你不能只重新连接一个基于连接的(读取,TCP)套接字。 但是,我看不到有关失败的connect()
意味着我们无法回收FD的任何信息。
如果连接中断,恢复连接是TCP的一个功能,通常会尝试这样做。
回答你的具体问题
很简单,在那里有大量的TCP实现。 虽然有些人可能会支持在一次失败之后再次进行connect()
调用,但其他人将会得到状态信息,使得这样做不可靠。
为了安全起见,必须有某种reset()
操作将套接字返回到原始状态。 由于这不包括在原来的(或任何后续的)TCP执行中,唯一剩下的选择是关闭并重新打开。
POSIX标准(以及您的书,可能使用POSIX标准作为参考)因此告诉您要做到这一点,以便能够使用所有支持TCP / IP的操作系统。 否则就会使一些现有的实现失效。
另外,新的实现可以自由地简化它们的实现,而不必担心尝试失败后启动新的连接。 这会导致更少的代码和更少的蠕虫进入。
你确定你正在使用相同的套接字 ,而不是你尝试连接到同一个地址的新套接字吗?
即使这是你正在做的事情,你正在试验的特定操作系统的事实允许重用一个未能连接的套接字并不意味着所有其他的操作系统实现套接字API(或更早/更高版本同样的操作系统)将同样宽松,所以你冒险生产巧妙的非可移植的代码。
当你做的事情,API合同不承诺,你会工作,一般不知道会发生什么。 一个可能的反应是,它似乎工作 – 直到付费客户尝试在他的机器上运行你的代码的时刻。
这种风险是否真的值得close(socket); socket=socket(...);
的成本close(socket); socket=socket(...);
close(socket); socket=socket(...);
在一个相当罕见的错误情况?