8

在 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 上启动了服务器。从主机上拔下网线。然后我在主机 A 上启动客户端。在同一个套接字上进行了大约 9 次不成功的连接尝试后,我只需将网络线插回服务器主机。客户端连接成功并愉快地以 80K/秒的速度发送消息。

在另一个实验中,我从服务器主机上拔了线,在最初的成功连接和几百万条消息交换之后。然后,几分钟后,我连接了电线,消息流在同一个套接字上恢复。

4

5 回答 5

7

POSIX 2001在信息部分中说:

如果connect()失败,则未指定套接字的状态。符合要求的应用程序应在尝试重新连接之前关闭文件描述符并创建新套接字。

因此,您引用的段落与此规范一致。它在您的机器上工作的事实并不意味着您的程序是可移植的。

于 2012-10-28T15:08:54.677 回答
2

这可能植根于connect 的联机帮助页,其中说:

一般来说,基于连接的协议套接字可能connect()只成功一次;无连接协议套接字可能会使用 connect() 多次来更改它们的关联。

这意味着您不能只重新连接基于连接的(读取,TCP)套接字。但是,我看不到它connect()表明我们无法回收 FD 的失败。

如果连接中断,恢复连接是 TCP 的一个特性,它通常会尝试这样做。

于 2012-10-28T15:06:39.537 回答
1

要回答您的具体问题...

很简单,那里有大量的 TCP 实现。虽然有些人可能支持connect()在一次失败后进行另一次呼叫,但其他人将拥有状态信息,这会使这样做不可靠。

为了安全起见,必须进行某种reset()操作以将套接字返回到原始状态。由于这不包括在最初的(或任何后续的)TCP 实现中,剩下的唯一选择是关闭并重新打开。

因此,POSIX 标准(以及您的书,可能使用 POSIX 标准作为参考)告诉您完全这样做,以便能够与所有支持 TCP/IP 的操作系统一起工作。否则会导致一些现有实现无效。

此外,新的实现可以自由地简化它们的实现,不必担心在尝试失败后启动新连接;这导致更少的代码和更少的错误潜入的机会。

于 2012-10-29T17:56:17.140 回答
1

您确定您使用的是相同的套接字,而不是您尝试连接到与以前相同的地址的新套接字吗?

即使这是您正在做的事情,您正在试验的特定操作系统允许重用无法连接的套接字这一事实并不意味着所有其他实现套接字 API(或更早/更高版本)的操作系统相同的操作系统)将同样宽松,因此您可能会产生微妙的不可移植代码。

当你做 API 合约没有承诺你会工作的事情时,通常不知道会发生什么。一种可能的反应是它似乎可以工作——直到付费客户试图在他的机器上运行你的代码。

close(socket); socket=socket(...);在相当罕见的错误情况下,这种风险真的值得付出代价吗?

于 2012-10-28T15:04:21.387 回答
0

套接字在 macOS Sierra 上的 Python 2 中确实变得不可用

$ python
>>> import socket
>>> s = socket.socket()
>>> s.connect(('127.0.0.1', 8888))
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/socket.py", line 228, in meth
    return getattr(self._sock,name)(*args)
socket.error: [Errno 61] Connection refused

>>> s.connect(('127.0.0.1', 8888))
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/socket.py", line 228, in meth
    return getattr(self._sock,name)(*args)
socket.error: [Errno 22] Invalid argument
>>> s.close()
>>> s.connect(('127.0.0.1', 8888))
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/socket.py", line 228, in meth
    return getattr(self._sock,name)(*args)
  File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/socket.py", line 174, in _dummy
    raise error(EBADF, 'Bad file descriptor')
socket.error: [Errno 9] Bad file descriptor

例如,如果您通过循环连接到服务器来等待服务器启动,就会出现这种情况。在这种情况下,在 macOS 上,您不能重用单个套接字来执行此操作。

于 2019-03-10T22:02:49.270 回答