【问题标题】:Trouble when trying to define a write_all() socket function in C尝试在 C 中定义 write_all() 套接字函数时出现问题
【发布时间】:2011-11-23 12:38:27
【问题描述】:

我目前在一个 C 客户端程序中使用这个函数。一切似乎都正常,但是当此客户端连接的服务器关闭时,write_all() 返回 4(即len)而不是预期的 -1。

int write_all(int sock, const void *buf, size_t len)
{
    int buf_size = len;
    while(len > 0)
    {
        int result = write(sock, buf, len);
        if(result < 0)
        {
            if(errno == EINTR)
                continue;
            return result;
        }
        buf += result;
        len -= result;
    }
    return buf_size;
}

这个函数有什么我遗漏的吗?我可以提前调用其他任何函数来确保服务器仍然正常运行吗?

谢谢

【问题讨论】:

  • write 可能会返回0,具体取决于套接字的类型。你有想过吗?
  • 我有。但是对于手头的问题,它并没有什么不同。是吗?
  • buf 是您的接收缓冲区还是发送缓冲区?在关闭服务器之前,您对客户端采取了哪些操作?服务器是否在同一台计算机上?
  • 测试是在同一台计算机上使用服务器进行的。在连接 + 关闭服务器 + 发送此写入消息之前,我没有做任何事情。 buf 是发送缓冲区。

标签: c sockets unix posix


【解决方案1】:

你说“关机”,你的意思是你关掉电源,没有优雅地关闭 TCP 吗?

在这种情况下,write 调用返回成功。数据在 TCP 发送缓冲区中,并且 TCP 堆栈还不知道对等方已关闭。程序在以后的调用中会出现 EPIPE 或其他错误。

TCP 堆栈会尝试重新传输一段时间,然后再做出连接失败的决定。

【讨论】:

  • 是的,服务器是故意崩溃的。那么,我应该如何继续检查服务器是否仍在运行或关闭?
  • 我这种情况下,客户端不知道是服务器宕机,还是网络暂时出现问题(流量太大等)。所以最好还是继续。客户端可能会在发送后调用 recv()/read()。如果服务器关闭,则接收呼叫将在一段时间后失败。此时您可以进行必要的操作。
  • 我的同事有类似的代码,当尝试写入关闭的套接字时会喊出“Broken pipe”错误。因此,客户端必须有一种方法可以知道服务器何时关闭。我从表面上看了一下他们的代码,我会说 99% 是一样的。必须有一些标志或有所作为的东西。
  • write()返回它应该写入的完整字节数,以防所有数据的传递已被确认由接收方(因为这是 TCP)?在这种情况下,这意味着服务器端服务器宕机之前至少已完全接收到数据。
  • 也许吧。然而我需要一个解决方案:(在尝试将数据发送到关闭的服务器时,是否有办法强制管道消息中断?
【解决方案2】:

对我来说,这看起来你不会绕过实施某种握手。

好像您的发件人仅知道它发送的数据已被完全接收(我假设是这种情况)是不够的,但它还需要知道接收者是否对其进行了任何类型的处理,您对套接字机制的期望超出了他们所能提供的范围......

插座只是发射器。

【讨论】:

  • 如另一篇文章中所述,我见过其他类似的项目,其中在尝试对关闭的服务器进行 write() 时,套接字以某种方式“抛出”了损坏的管道错误。所以一定有办法。
  • @devoured elysium:他们确实这样做了,以防他们无法提供(全部)他们的数据。无论如何,在您的情况下,在我看来,服务器确实正确地接收了发送的数据完成之前。如果服务器没有读取它(全部),write() 将不会返回它应该写入的字节数(如前所述...... ;-) 但 -1 并将 errno 最可能设置为 EPIPE .
  • 以往任何事情:如果您的客户知道它发送的任何数据是否丢失真的很重要,您可能会开始考虑使用应用程序/级别的握手协议。
【解决方案3】:

注意:我在这里假设 TCP。

从返回值中,我了解到客户端在得知服务器关闭其结束或以其他方式消失之前设法将 4 个字节写入发送缓冲区。如果它在没有适当关闭的情况下消失了,唯一知道的方法就是发送超时。之后的writeshutdownclose 会报错。

如果您想在无需不断发送数据的情况下获得端点消失的提示通知,您可以激活套接字保持活动选项。在 Linux 中,这将是 setsockopt(..., SOL_SOCKET, SO_KEEPALIVE, ...)TCP_KEEPIDLETCP_KEEPINTVLTCP_KEEPCNTSOL_TCP 级别。

【讨论】:

    猜你喜欢
    • 2011-04-22
    • 2019-04-05
    • 2021-05-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-10-31
    • 1970-01-01
    相关资源
    最近更新 更多