连接失败时重用套接字描述符

13

在我的客户端代码中,我按照以下步骤连接到套接字:

  1. 创建一个套接字

  2. sockDesc = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)  
    
  3. 连接它(在失败的情况下重试 'x' 次)

  4. connect(sockDesc, (sockaddr *) &destAddr, sizeof(destAddr))  
    
    在填充destAddr字段后,使用套接字进行send()/recv()操作:
    send(sockDesc, buffer, bufferLen, 0)  
    recv(sockDesc, buffer, bufferLen, 0)  
    
  5. close() 关闭套接字描述符并退出

  6. close(sockDesc)  
    
    如果在send()/recv()期间连接中断,我发现可以通过返回第2步来重新连接。
    这个方法可行吗?我应该关闭套接字描述符并返回第1步吗?
    另一个有趣的观察是,当我停止回声服务器并启动客户端时,我创建了一个Socket(第1步),然后调用connect(),它失败了(如预期),但是我仍然不断调用connect(),比如说,10次。经过5次重试后,我启动了服务器,并且connect()成功了。但是在send()调用期间,它收到了SIGPIPE错误。我想知道:
    1)每次connect()失败时,我需要创建一个新的套接字吗?据我所知,在套接字上没有执行任何send()/recv()操作之前,它就像新的一样,并且我可以重复使用相同的fd进行connect()调用。
    2)我不明白为什么在服务器启动且connect()成功时会收到SIGPIPE

在按建议更改代码并关闭套接字描述符、创建新的套接字并连接后,SIGPIPE问题不再出现。 - Adil
1
我发现这个链接很有用,与你的问题相关,因为你使用了send而不是write: https://dev59.com/il_Va4cB1Zd3GeqPW8zE - Rodrigo Gurgel
5个回答

7

是的,您应该关闭并返回第1步:

close()函数关闭文件描述符, 以便它不再引用任何文件 并可以被重复使用。

来自这里


有任何特定的原因吗?由于我在重新连接服务器时在connect调用中使用相同的fd,而不创建任何新套接字,所以这不应该会有什么影响吧?或者在这种情况下套接字会进入等待状态之类的情况吗? - Adil
规格说明表明,“文件”不再指任何东西。对我来说,这表明句柄仍然有效,但需要重新初始化。 - Hassan Syed

5

我认为关闭套接字是正确的做法,尽管如果不这样做可能会起作用。

连接失败的套接字可能与全新的套接字状态不完全相同,这可能会在以后引起问题。我宁愿避免可能性,直接创建一个新的。这更加清晰。

TCP套接字保存了大量的状态,其中一些是特定于实现并从网络中解决的。


4

1
如果我关闭描述符,我认为我需要重新创建套接字,因为关闭描述符意味着销毁套接字,对吗? - Adil
1
在一个套接字被 close() 关闭后,您不应再使用该套接字描述符。此时它已经无效了。请使用 socket() 获取一个新的套接字描述符。 - alk

3
如果连接中断并且您尝试在文件描述符上写入数据,则应该会收到“broken pipe”错误/信号。这只是意味着您尝试写入的文件描述符不再有任何人在另一端读取您发送的内容。
您可以捕获SIGPIPE信号,然后通过关闭FD并返回步骤1来处理重新连接。现在您将拥有一个新的FD,可以从中读取和写入连接。

2
如果Single UNIX规范没有明确说明必须回到步骤#2而不是步骤#1,那么它在Linux上能够工作只是一种实现细节。如果您回到步骤#1,则更具可移植性。据我所知,规范没有保证可以回到步骤#2,因此我建议您回到步骤#1。

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