C语言中的套接字通信。发送文件内容

Posted

技术标签:

【中文标题】C语言中的套接字通信。发送文件内容【英文标题】:Socket communication in C language. Sending file contents 【发布时间】:2018-12-10 08:02:33 【问题描述】:

所以前几天我得到了一个相对简单的任务,那就是构建一些客户端和一些服务器代码,其中服务器接收消息并返回其当前系统时间。这并不难,我交付并获得了一个简单的标记。

我开始考虑更多,我决定开始尝试发送特定文件的内容服务器 --> 客户端(服务器将内容发送到客户端)。虽然我正在构建我经常在本地测试的代码并且它按预期工作,但当我将服务器代码上传到运行 Ubuntu 的服务器(哈哈)时,真正的问题出现了。启动服务器,一切正常,启动客户端,请求“index.html”和BAM!一半文件没有收到。 服务器打印它(我做了它,所以它在发送时打印文件的内容,这样我就可以更轻松地进行故障排除)。

我现在一直在寻找一些东西,每次我发现一些看起来很有用的东西时,它都会以不同的编程语言结束,并且在 C 中找不到任何等价物。

在客户端和服务器代码中使用休眠似乎可以解决这个问题,但我认为这不是一个好习惯。

代码很乱,所以我将包含我认为相关的内容,我还将包含完整代码的链接。我真的想改进它,但在尝试解决这个问题时失去了动力,我只是让它变得更糟。

客户端

printf("Please specify the filename: ");
fgets(msg,1000,stdin); // get message from std input

if(strcmp(msg,"\n")==0) 
    printf("Wrong file name or format\n");
    printf("Please specify the filename: ");
    fgets(msg,1000,stdin); // get message from std input



while(strcmp(msg,"!stop\n")) 

    msg[strlen(msg)-1]='\0';
    write(sockfd,msg,strlen(msg));
    FILE *fp = NULL;

    char filecontent[1000];
    bzero(filecontent,sizeof(filecontent));


    while(  (n = read(sockfd,filecontent,1000)) && strcmp(filecontent,"Over and out!")!=0  ) 

        if(strcmp(filecontent,"No such file")!=0 && fp == NULL) 
            fp = fopen(msg,"w");
        

        printf("%s",filecontent);

        if(fp !=NULL)
            fprintf(fp, "%s",filecontent);

        bzero(filecontent,sizeof(filecontent));
    

    if(fp != NULL)
        fclose(fp);

    printf("\nPlease specify the filename: ");
    fgets(msg,1000,stdin); // get message from std input


    if(strcmp(msg,"\n")==0) 
        printf("Wrong file name or format\n");
        printf("Please specify the filename: ");
        fgets(msg,1000,stdin); // get message from std input
    


服务器端

   char date[50];
time_t ticks;
struct tm *tinfo;
time(&ticks);
tinfo=localtime(&ticks);
strcpy(date,asctime(tinfo));
printf("DATA: %s\n",date);
write(newsocketfd,date,sizeof(date));

while( (n = read(newsocketfd,msg,1000)) && strcmp(msg,"!stop\n")!=0) 
    //printf("MSG: %s\n",msg);

    if(n<0)
        error("ERROR READING");
    /////////READING FILE/////////////


    char *filename = malloc(sizeof(msg)+1);
    strcpy(filename,msg);
    printf("'server filename:%s'\n",filename);
    FILE *fp = fopen( filename,"r");

    if(fp == NULL) 
        printf("No such file found\n");
        write(newsocketfd,"No such file",sizeof("No such file"));
    

    while( fp!=NULL && fgets(msg,1000,fp)!=NULL)
        write(newsocketfd,msg,sizeof(msg));
        msg[strlen(msg)-1]='\0';
        printf("server: '%s'\n",msg);
        bzero(msg,sizeof(msg));

    


bzero(msg,sizeof(msg));
bzero(filename,strlen(filename));
n = write(newsocketfd,"Over and out!",sizeof("Over and out!"));
printf("Over\n");


很抱歉让您头疼。 Full code here.

示例:

I think this pretty much shows the problem

我的想法是,服务器逐行读取文件,并将其逐行发送给客户端,完成后服务器发送“结束”并且客户端停止从那里读取,但似乎客户端永远不会收到所有信息或“结束”信号。值得补充的是,如果我在本地机器上运行这两个代码,这将非常有效。

【问题讨论】:

要调试你的程序,你可以使用wireshark来检查网络上发送了什么 我认为这不是发送什么而是接收什么的问题,我可以从打印收到的信息中看出这一点。尽管如此,我会调查一下,谢谢! 您应该检查服务器端的返回值frm write() 以检查实际发送了多少字节...write() 不能保证发送所有传递给它的数据。 @Nunchy 是的,处于阻塞模式。 你犯了书中的每一个错误。 (1) strlen()strcmp() 在接收到的数据上:没有任何东西可以保证尾随空值的存在。 (2) 在错误之后继续进行,就好像它没有发生一样。 (3) 在read()/recv() 之前的bzero() 是多余的。 (3) 忽略read()/fread() 返回的长度,假设它填满了缓冲区。这个网站充满了正确的例子。 【参考方案1】:

欢迎来到网络编程的世界!网络协议分层是有原因的。当您在 TCP 套接字上发送内容并立即关闭套接字时,传递是不可靠的:它可能会正确传递给对等方,或者可能由于竞争条件而消失。

唯一可靠的方法是仅在对等方发送它可以接收已发送的所有内容的确认时关闭套接字。标准协议为此使用控制消息,您确实应该考虑这一点,但如果您不需要警告服务器客户端故障,您可以简单地让客户端在收到"Over and out!" 时关闭连接。顺便说一句,您应该知道,由于 TCP 是一种流协议,因此没有什么可以保证消息不会被拆分为多次读取,或者连接到其他字节。因此,您应该保留上一次读取的结尾(信号字符串的大小减去一个字节),将下一次读取连接到该字符串并在缓冲区中的任何位置搜索字符串。

另一种常见的方法是使用graceful shutdown:发送方使用shutdown(socket.SHUT_WR) 表示通信结束没有关闭套接字并等待(使用read)对等方一切都正确交付后关闭套接字。

【讨论】:

以上是关于C语言中的套接字通信。发送文件内容的主要内容,如果未能解决你的问题,请参考以下文章

Linux C语言高级编程之使用消息队列实现进程间通信!重点内容!!!

一起talk C栗子吧(第一百六十回:C语言实例--套接字通信模型二)

通过c中的套接字发送结构

20193120 实验三《Python程序设计》实验报告

20193120 实验三《Python程序设计》实验报告

一起talk C栗子吧(第一百六十回:C语言实例--套接字通信模型一)