【问题标题】:C Sockets: write() followed by close() results in incomplete data transferC 套接字:write() 后跟 close() 导致数据传输不完整
【发布时间】:2014-12-03 21:21:39
【问题描述】:

我正在尝试编写一个基本的文件服务器,它从客户端获取文件名并通过通过 TCP 向客户端发送数据来响应。我有一个大部分工作的客户端和服务器应用程序,但我观察到一些奇怪的行为,请考虑以下

    while ((num_read = read (file_fd, file_buffer, sizeof (file_buffer))) > 0)
    {
        if (num_read != write (conn_fd, article_buffer, num_read))
        {
            perror ("write");
            goto out;
        }
    }
    out:
           close(file_fd); close(sub_fd);

file_fd 是通过网络发送的文件的文件描述符,conn_fdconnect()ed TCP 套接字的文件描述符。

这似乎适用于小文件,但是当我的文件变大(兆字节+)时,文件末尾的一些不一致的数据量似乎将无法传输。

我怀疑写入后的立即 close() 语句可能与它有关,因此我在两个 close() 语句之前尝试了 1 秒 sleep(),我的客户成功收到了所有数据。

有没有比在服务器端执行sleep() 更好的方法来处理这个问题?

【问题讨论】:

  • 这里演示的是客户端代码还是服务端代码?
  • fsync(2) 怎么样?
  • 我试过 fsync() 并没有解决问题。
  • 我认为您还有其他问题。除非网络中断,否则 TCP 套接字不会像那样丢弃数据。
  • 您也应该检查read()close() 的返回值(特别是-1 和它的errno)。不仅在这种情况下,而且在一般情况下。

标签: c sockets tcp network-programming file-descriptor


【解决方案1】:

套接字上的成功“写入”并不意味着数据已成功发送到对等方。

如果您使用的是 unix 衍生产品,则可以执行“man 7 socket”并检查 SO_LINGER”作为潜在的解决方案。

编辑:由于 EJP 的评论(谢谢),我重新阅读了 Stevens 在“Unix 网络编程”中关于确保将所有数据传递给对等点的主题所说的话。他说如下(第二版第 1 卷,第 189 页):

...我们看到,当我们关闭连接结束时,取决于调用的函数(关闭或关闭)以及是否设置了 SO_LINGER 套接字选项,返回可能发生在三个不同的时间。

  1. close 立即返回,无需等待(默认设置;图 7.6)
  2. close 一直持续到收到我们的 FIN 的 ACK(图 7.7),或者
  3. 关机后读取等待,直到我们收到对等方的 FIN(图 7.8)

他的数字和他的评论表明,除了“应用程序级别确认”之外,shutdown() 的组合,后面跟着一个 read() 等待零返回码(即通知套接字已关闭),是确保客户端应用程序已收到数据的唯一方法。

但是,如果仅重要的是数据已成功交付(并确认)到对等计算机,那么 SO_LINGER 就足够了。

【讨论】:

  • SO_LINGER 并没有真正解决这个问题,它只是可以检测当最终挂起的数据无法写入时。在这种情况下,问题几乎肯定出在接收端。
猜你喜欢
  • 2014-10-18
  • 1970-01-01
  • 2018-06-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-09-28
相关资源
最近更新 更多