2010-01-29 71 views
2

我想用C发送文件到特定的套接字;下面的代码:发送文件到套接字

int send_file(char *filepath,int sock) 
{ 
    FILE *fp=fopen(filepath,"rb"); 
    void *buff=malloc(2000); 
    int i=1; 
    while(i) 
    { 
     int bytes_read=fread(buff,1,2000,fp); 
     i=!(feof(fp)); 
     int bytes_sent=0; 
     while(bytes_sent<bytes_read) 
     { 
      int n=send(sock,buff+bytes_sent,bytes_read-bytes_sent,0); 
      if(n==-1) 
       return -1; //failure 
      bytes_sent+=n; 
     } 

    } 
    fclose(fp); 
    free(buff); 
    return 0; 
} 

当我运行这个程序,并尝试在Firefox中的文本文件在http://127.0.0.1:8080/,文件的一部分从最终切断如果文件大小超过2000个字节。如果我发送一张图片,只有图片的3/4加载(从底部切下)。

该函数总是返回0给调用者。它发送的最后一个字节块在哪里消失?在返回之前是否需要刷新一些流?

谢谢

编辑: 这是一个片段从我的main()函数:

send_file(filepath, sock); 
close(sock); 
return 0; 
} 
+0

你确定了“失败”路径没有发生?您应该在此时向标准错误输出错误消息,而不是仅返回-1。 – 2010-01-29 20:27:59

+0

是的,我检查了它返回到main的值,它总是0. – io555782 2010-01-29 20:56:26

+0

你能编译带有最大警告的代码并发布警告吗?你是否包含stdio.h,stdlib.h和sys/socket.h? – 2010-01-30 03:55:56

回答

1

有一个标准的API为这个!使用sendfile()

内核会在没有上下文切换的情况下进行复制,从而实现更高的效率。

+1

这根本不是标准的。根据http://linux.die.net/man/2/sendfile - “未在POSIX.1-2001或其他标准中指定,其他Unix系统使用不同的语义和原型实现sendfile(),不应该使用在便携式程序中。“ – 2010-01-29 19:44:00

1

你永远不应该使用feof(),它几乎总是做错的事情。相反,使用fread()的返回值来确定何时读取了所有内容 - 只要它不为零,就需要继续阅读和发送。在伪代码中:

while(1) { 
    r = fread(...); 
    if (r == 0) { 
     break; 
    } 
    send(..); 
} 
+0

修改后的代码,仍然会出现同样的问题..我在浏览器中看到的文本在某一时刻被切断。 :| – io555782 2010-01-29 20:00:46

+0

@ io555782只要您使用eof() – 2010-01-29 20:02:44

+0

您发布的代码将无法正常工作我按照您的说法修改了它(不含feof())http://pastebin.com/f29a656b0;最后还是会截断一些文字。 – io555782 2010-01-29 20:10:23

0

我看不到剩余的程序,但我怀疑在关闭套接字之前退出。

如果套接字完成发送其数据之前,你的程序退出时,操作系统是没有义务做剩余的未发送任何数据,而且可能把它扔出去。

0

您发布的代码对我来说看起来没问题。尼尔说,feof问题可能存在,尽管它使用微软的编译器可以正常工作。我测试了它的发送呼叫存根,并且所有数据都被“发送”了。在我看来,这个错误可能在接收端。一个简单的测试就是简单地打印两端发送和读取的文件长度。确保recv调用获取所有刷新的数据。

+0

谢谢。我用来测试这个代码的接收端是一个web浏览器,但不是我写的程序。 – io555782 2010-01-29 20:59:10

+0

啊 - 对。你在你的帖子中提到,我马上忘记了。我想咱可能会想到一些事情。 – 2010-01-29 21:18:42

0

如果您使用网络浏览器查看文件,则应在发送实际数据之前发送HTTP标头。

我只是猜测,但最有可能的,在标题,你发送的数据的大小为2000个字节。因此,即使您发送的字节数超过2000,浏览器也不会期待它们,并且只显示前2000个字节。

此外,因为您要关闭连接,你should send Connection: close header到客户端。

0

阅读所有的Web浏览器发送给您的数据?如果你不是(这是可以理解的,如果你实际上没有编写Web服务器),那么调用close()带有未读数据会引发TCP连接中止而不是干净关闭。

干净关闭等待所有未完成的数据发送;中止不会导致未完成的数据丢失。

出于测试目的,你应该能够把这个在发送功能的结束(你免费buff)之前进行修复:

shutdown(sock, SHUT_WR); /* Send EOF to web browser */ 
while (recv(sock, buff, 2000, 0) > 0) 
    ; /* Read and discard until we see the browser's EOF (or an error) */