【问题标题】:read system call on socket stuck [C language] - failed to send binary file over socket读取套接字上的系统调用卡住 [C 语言] - 无法通过套接字发送二进制文件
【发布时间】:2016-05-30 15:56:57
【问题描述】:

我有客户端服务器架构,其中我将二进制文件从服务器传输到客户端。

服务器代码:

            FILE *outFile = fopen("/tmp/localpkg.deb","wb");
            if( outFile == NULL )
            {
                     RPTLOG(1, "Error opening file for writing.\n");
                     return -1;
            }

            FILE *readFilefp = fopen(file_name, "rb");

            if ( readFilefp == NULL)
            {
                     RPTLOG(1, "Error opening file.\n");
                     return -1;
            }

            char fileBuffer[1024];
            bzero(fileBuffer, 1024);

            while(1)
            {

                    size_t readSize = fread(fileBuffer, sizeof(char), sizeof(fileBuffer) -1, readFilefp);

                    if(readSize == 0)
                    {
                            RPTLOG(1, "No more contents are left in file.\n");
                            n = write(sockfd, "\r\n", 2);
                            break;
                    }

                    n = write(sockfd, fileBuffer,readSize);

                    fwrite(&fileBuffer, sizeof(char), readSize, outFile);

                    RPTLOG(1, "Data[%d] written to sock=%s.\n", n, fileBuffer);
                    bzero(fileBuffer, 1024);

            }

            fclose(readFilefp);
            fclose(outFile);

            char *endfile_var =(char*) malloc(2048);
            bzero(endfile_var,100);
            strcpy(endfile_var,"ENDFILE\r\n");

            n = write(sockfd, endfile_var, 9 );

            RPTLOG(1, "ENDFILE text sent to client[%s] NumBytes sent=%d\n", endfile_var, n );

客户端代码:

                   FILE *fp = fopen(localfile, "wb");
                    if( fp == NULL )
                    {
                            RPTLOG(1, "Not enough permissions to write on disk, exiting....\n");
                            break;
                    }

                    memset(buf, 0, 2048);

                    //Started receiving installation package from server
                    while ((ret = read(sock, buf, 2047)) > 0) //Stcuk point: read blocks over here when it is about to receive last few lines of
                    {                                         //binary file from server

                            buf[ret] = '\0';

                            if ( ret == 1 )
                            {
                                    RPTLOG(1, "Caught character  where ret = %d\n", ret);
                                    if ( buf[0] == '\n' )
                                            continue;
                            }

                            if (strstr(buf, "ENDFILE") != 0 )
                            {
                                    RPTLOG(1, "Endfile detected\n");
                                    break;
                            }
                            else
                            {
                                    fwrite(buf, 1, ret, fp);
                            }

                            memset(buf, 0, 2048);

                    }

                    if( ret ==  0)
                    {
                            RPTLOG(4, "Connection closed from server = %d \n", ret );
                    }
                    else if( ret <  0)
                    {
                            RPTLOG(4, "Read error on client socket= %d \n", ret );
                    }

                    fclose(fp);

我的问题: 当服务器即将发送最后几行二进制文件时,客户端卡在读取调用 [上面发布的客户端代码中的卡点]。这里客户端程序的设计方式是,当它从服务器接收到“ENDFILE”行时,它将假定文件内容已经从服务器端结束并退出while循环。

所以请提出从服务器成功接收二进制文件的解决方案。

[特别说明:]客户端代码已打包在构建中并安装在客户端。所以我只需要对服务器端代码进行更改。同样如上面的服务器代码所示,出于调试目的,我还将通过套接字发送的内容写入“/tmp/localpkg.deb”文件。并且该文件包含了在服务器端的套接字上写入的所有内容。

[特别说明2:] 当我尝试发送纯文本文件时,我可以发送成功。问题仅在发送二进制文件时出现。 提前致谢。

【问题讨论】:

  • 检查服务器发送了多少字节,然后与客户端接收到的字节进行比较。如果没有更多数据可以从套接字读取,客户端将继续等待。
  • 真的很糟糕的设计,如果链接必须处理带有ascii代码的二进制数据检查真的没有意义。二进制文件可以包含任何内容,甚至是空字节。如果您在ENDFILE 代码之前有一个,则传输结束检查将始终失败!
  • Cargo-cult 'memset(buf, 0, 2048);', 'buf[ret] = '\0';'并且对于二进制传输都无用:(
  • @MartinJames,第二个 OP 必须要做,因为 OP 正在调用 strstr。真正的货物在这里:char *endfile_var =(char*) malloc(2048); bzero(endfile_var,100); strcpy(endfile_var,"ENDFILE\r\n"); :)
  • @SergeyA 哦,我相信你。我没有看服务器代码,我确定这也有“问题”:(

标签: c linux sockets socket.io raw-sockets


【解决方案1】:

您的代码失败的原因很简单。您正在将一大块 binary 数据读入您的 buf,然后在此 buf 上调用 strstr。在查找给定令牌时,strstr 直到第一个 \0 字节。显然,二进制数据会有很多这样的数据,因此在遇到第一个数据后搜索停止并返回“未找到任何内容”。

因此,您的代码永远不会退出读取循环,并一直等待更多数据从服务器到达 - 服务器永远不会发送它。

当然,正确的解决方案是实施适当的协议来发送二进制数据。但是,如果由于列出的限制而无法做到这一点,则半可行的解决方案是将strstr 函数替换为自定义函数,该函数将忽略提供的缓冲区而忽略 nul 终止符(改为使用缓冲区的大小) 并查找提供的令牌。如果您的二进制数据中包含令牌,它仍然会中断,但您无能为力。

【讨论】:

  • 大声笑,从标题来看,肯定是滥用 str* 调用:)
猜你喜欢
  • 2011-12-03
  • 1970-01-01
  • 1970-01-01
  • 2023-03-02
  • 1970-01-01
  • 2012-08-23
  • 2012-10-11
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多