gpt4 book ai didi

C套接字,不完整的文件传输

转载 作者:太空宇宙 更新时间:2023-11-04 00:05:38 25 4
gpt4 key购买 nike

我正在编写一个 C 程序来传输一个固定大小的文件,该文件大小超过 2Mb,从服务器到客户端。我在 Linux 上使用 TCP 套接字,我编写的代码如下:

服务器(发送方)

while (1) {
int nread = read(file, buffer, bufsize);
if (nread == 0) // EOF
break;

if (nread < 0) {
// handle errors
}

char* partial = buffer;
while (nread > 0) {
int nwrite = write(socket, partial, nread);
if (nwrite <= 0) {
// handle errors
}
nread -= nwrite;
partial += nwrite;
}
}

// file sent
shutdown(socket, SHUT_WR);

客户端(接收方)

while (filesize > 0) {
nread = read(socket, buffer, bufsize);
if (nread == 0) {
// EOF - if we reach this point filesize is still > 0
// so the transfer was incomplete
break;
}

if (nread < 0) {
// handle errors
}

char* partial = buffer;
while (nread > 0) {
nwrite = write(file, partial, nread);
if (nwrite <= 0) {
// handle errors
}
nread -= nwrite;
partial += nwrite;
filesize -= nwrite;
}
}

if (filesize > 0) {
// incomplete transfer
// handle error
}

close(socket);

在我的笔记本电脑上测试代码时(客户端和服务器“都”在本地主机上,并且通信发生在环回接口(interface)上),有时客户端会退出,因为read 收到一个EOF,而不是因为它收到了所有 filesize 字节。由于我在服务器上使用了shutdown,这应该意味着没有其他数据可以读取。(注意服务器发送了所有字节并正确执行了shutdown)

你能解释一下为什么会这样吗?

丢失的字节去哪儿了?

-----

编辑 1 - 澄清

一些用户要求澄清一些,所以我在这里发布答案:

  • 该程序正在使用TCP 阻塞 套接字
  • filesize 是一个固定值,在客户端和服务器中都是硬编码的。
  • 没有特殊的套接字选项,例如,启用/使用SO_LINGER
  • 发生错误时,服务器(发送方)已经发送了所有数据并正确执行了shutdown
  • 到目前为止,在不同机器上使用客户端和服务器测试应用程序时从未发生过该错误(通过真实网络接口(interface)而非环回接口(interface)传输)

编辑 2

用户 Jade 米杆 pointed me到一个非常有趣的article关于 TCP 的不总是可靠的行为。

这篇非常值得一读的文章描述了一些在 TCP 套接字之间发送未知数量的数据时有用的技巧。所描述的技巧如下:

  1. 利用发件人的 SO_LINGER 选项。这将有助于在调用 close(2)shutdown(2) 时保持套接字打开,直到所有数据已成功发送。
  2. 在接收器上,注意在实际接收循环之前挂起的可读数据。这可能会导致立即发送重置。
  3. 利用 shutdown(2) 通知接收方发送方已完成发送数据。
  4. 在实际发送文件之前让接收方知道将要发送的文件的大小。
  5. 让接收者向发送者确认接收循环结束。这将有助于防止发送方过早关闭套接字。

阅读这篇文章后,我升级了我的代码以实现技巧 1 和技巧 5。

这就是我实现技巧 5 的方式:

服务器(发送方)

// sending loop ...

// file sent
shutdown(socket, SHUT_WR);

// wait acknowledgement from the client
ack = read(socket, buffer, bufsize);
if (ack < 0) {
// handle errors
}

客户端(接收方)

// receiving loop..

if (filesize > 0) {
// incomplete transfer
// handle error
}

// send acknowledgement to the server
// this will send a FIN and trigger a read = 0 on the server
shutdown(socket, SHUT_WR);

close(socket);

技巧 2、3 和 4 呢?

技巧 2 不需要,因为一旦服务器接受连接,应用程序就会继续进行文件传输。不交换额外的消息。

技巧 3 已经实现

技巧 4 也已经实现。如前所述,文件大小是硬编码的,因此无需交换。

这是否解决了我原来的问题?

NO 我的问题没有解决。该错误仍在发生,截至今天,它仅在使用本地主机上的客户端和服务器测试应用程序时发生。

你怎么看?

有什么办法可以避免这种情况吗?

最佳答案

你是:

  1. 假设 read 填满了缓冲区,即使
  2. 您正在出色地防止 write() 不写入整个缓冲区。

您需要执行 (1),而您不需要执行 (2),因为您处于阻塞模式并且 POSIX 确保 write() 不会返回,直到所有数据写入。

两个循环的简单版本:

while ((nread = read(inFD, buffer, 0, sizeof buffer)) > 0)
{
write(outFD, buffer, 0, nread);
}
if (nread == -1)
; // error

当然,更正确的版本会检查 write() 的结果是否有错误。

关于C套接字,不完整的文件传输,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25476348/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com