【问题标题】:Reusing socket descriptor on connection failure在连接失败时重用套接字描述符
【发布时间】:2011-01-15 07:13:22
【问题描述】:

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

  1. 创建一个套接字

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

    connect(sockDesc, (sockaddr *) &destAddr, sizeof(destAddr))  
    

    (填写destAddr字段后)

  3. 使用socket进行send()/recv()操作:

    send(sockDesc, buffer, bufferLen, 0)  
    recv(sockDesc, buffer, bufferLen, 0)  
    
  4. close()套接字描述符并退出

    close(sockDesc)  
    

如果在send()/recv()期间连接中断,我发现返回步骤2可以连接。

这个解决方案好吗?我应该关闭套接字描述符并返回步骤 1 吗?

另一个我无法理解的有趣观察是 我停止我的回声服务器并启动客户端。我创建了一个套接字(第 1 步)并调用 connect() 失败(如预期的那样),但随后我继续调用 connect(),比方说 10 次。重试 5 次后,我启动服务器,connect() 成功。但是在send() 调用期间,它会收到SIGPIPE 错误。我想知道:

1) 每次connect() 失败时,我是否需要创建一个新套接字?根据我的理解,只要我没有在套接字上执行任何send()/recv(),它就和新的一样好,我可以将相同的fd 重复用于connect() 调用。

2) 我不明白为什么在服务器启动并且connect() 成功时收到SIGPIPE

【问题讨论】:

  • 按照建议更改代码关闭 scoket-descriptor 并创建新套接字并连接后,SIGPIPE 问题不再发生。
  • 我发现此链接很有用,并且与您的问题相关,因为您使用的是发送而不是写:stackoverflow.com/questions/9048959/…

标签: c linux sockets


【解决方案1】:

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

close() 关闭文件描述符, 这样它就不再指代任何 文件,可以重复使用。

来自here

【讨论】:

  • 有什么具体原因吗?由于我在连接调用中使用相同的 fd 来重新连接服务器并且没有创建任何新的套接字,它应该不会有害吗?或者在这种情况下套接字进入等待状态或什么?
  • 好吧,规范表明“文件”不再指代任何东西。对我来说,这表明句柄仍然有效,但需要重新初始化。
【解决方案2】:

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

连接失败的套接字可能与全新的套接字处于不同的状态 - 这可能会导致以后出现问题。我宁愿避免这种可能性,只做一个新的。它更干净。

TCP 套接字拥有很多状态,其中一些是特定于实现的,并且是从网络中得出的。

【讨论】:

    【解决方案3】:

    断开连接对应的套接字处于不稳定状态。通常除非操作系统释放套接字,否则您将无法再次连接。

    我认为 close() 并再次连接会更好。你不必创建另一个套接字。

    无论如何,请务必设置您的套接字的LINGER,以确保传输过程中不会丢失任何数据。

    http://www.gnu.org/s/libc/manual/html_node/Socket_002dLevel-Options.html#Socket_002dLevel-Options

    【讨论】:

    • 如果我关闭描述符,我想我需要再次创建套接字,因为关闭描述符意味着破坏套接字,对吧?
    • 在一个套接字被close()d 之后,你将不再使用套接字描述符。那就无效了。使用socket() 获取新的套接字描述符。
    【解决方案4】:

    如果连接断开并且您尝试在文件描述符上写入,您应该会收到损坏的管道错误/信号。这就是说,您尝试写入的文件描述符不再有另一端的任何人可以读取您发送的内容。

    您可以做的是捕获信号 SIGPIPE,然后通过关闭 FD 并返回到您的步骤 1 来处理重新连接。您现在将拥有一个新的 FD,您可以从中读取和写入连接。

    【讨论】:

      【解决方案5】:

      如果单一 UNIX 规范没有说它必须返回到第 2 步而不是第 1 步,那么它恰好可以在 Linux 上工作的事实只是一个实现细节,而您将远远不够如果你回到步骤#1,会更好,更便携。据我所知,规范并不能保证可以返回第 2 步,因此,我建议您返回第 1 步。

      【讨论】:

        猜你喜欢
        • 2011-03-31
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多