通过套接字进行文件传输,最终大小减少字节

6

我正在尝试通过C语言的套接字接收一些文件。但是服务器会以64字节的数据包发送1000000字节的文件,例如,而我在目标文件中只能获得大约999902个字节。

while ((n = read(sd, buffer_in, BUFSIZE ))) //  BUFSIZE = 64 
{
    if(n<0)
    {
       printf("Fail.\n");
       fclose(archivo);
       return -1;
    }

    if(fwrite(buffer_in, n, 1, f) !=1 ) 
    { 
       printf("fwrite error.\n");
       fclose(archivo);
       return -1;
    }

    bytes+=n;
}

printf("We received %d bytes",  bytes);

当通过本地TCP/IP套接字使用时,它可以工作,但在慢速连接中无法工作。通过调试,我发现我得到了许多64字节的块,并在EOF附近得到了一个30字节的块。我知道在read()上可以获得更少的字节,因为当任何数据(> 1个字节)可用时,调用返回。但是这种情况不应该被while捕捉到吗?应该在n == 0时返回,即没有更多数据(EOF)。
感谢您的帮助。
(编辑)
发送代码如下:
while (n=read(file_fd, buffer, BUFSIZE))
{
   write (sdaccept, buffer, n)
}

我知道read()和write()都可能返回N<BUFSIZE,但是这个循环不应该相应地解决吗? 我添加了n并返回1000000,确切的大小。
(第二次编辑)
用10673字节的C源代码测试,可以接收10575字节而没有损坏,除了目标文件缺少前98字节之外!!!

大约是999902吗?还是确切的数字? - paxdiablo
我在这段代码中没有发现明显的缺陷 - 请同时展示发送代码。 - Alnitak
尤其奇怪的是,64可以完全地除以1000000。 - Mitch Wheat
已添加发送代码... Pax: 是的,999902 正好来自一个 1 百万字节的文件。 - Hernán
你应该测试 while ((n = read(...)) > 0)。目前即使出现错误 (n == -1),你仍在继续执行。 - user207421
1个回答

11

发送代码忽略了一个事实:在套接字上调用write()(或send())时,不一定会写入整个缓冲区。

如果底层子系统拒绝接收更多数据(例如,网络子系统可能有一个用于要发送的数据的队列,而此队列已经满了),则write()/send()可能会部分地写入数据或根本不写入数据。在慢速连接上,这很可能发生。

发送方应该检查write()的返回值以检测实际写入了多少数据,并相应地进行调整。

应该像这样执行写操作:

int readAmount;
while( readAmount = read(file_fd, buffer, BUFSIZE) > 0 )
{
    int totalWritten = 0;
    do {
       int actualWritten;
       actualWritten = write (sdaccept, buffer + totalWritten, readAmount - totalWritten);
       if( actualWritten == - 1 ) {
           //some error occured - quit;
       }
       totalWritten += actualWritten;
    } while( totalWritten < readAmount );
}

发送代码恰好容易出现我所描述的问题。建议修复已添加。 - sharptooth
你的意思是,你将所有迭代的totalWritten相加,结果为1M,但接收方仍然接收到不完整的数据? - sharptooth
你应该尝试准确地检测缺失的数据。例如,在从磁盘读取块之后,将一个整数写入其前四个字节并递增该整数。在接收端检查它。 - sharptooth
看,这不是我的代码,我正在修复一个混乱的情况。在接收器中读取之前,通过同一套接字发送如何?该程序在 while 循环之前将文件名发送到服务器。也许还有一些字符留在那里?我需要刷新该套接字.. :) - Hernán
这个答案是不正确的。在阻塞模式下,POSIX 要求 write()send() 在返回之前传输所有数据,除非出现中断或错误。 - user207421
显示剩余8条评论

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