在卡住的套接字上读取系统调用 [C 语言] - 无法通过套接字发送二进制文件
read system call on socket stuck [C language] - failed to send binary file over socket
我有客户端服务器架构,其中我将二进制文件从服务器传输到客户端。
服务器代码:
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] = '[=11=]';
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:]当我尝试发送纯文本文件时,我可以成功发送。只有在发送二进制文件时才会出现问题。
提前致谢。
您的代码失败的原因很简单。您正在将一大块 binary 数据读入您的 buf,然后在此 buf 上调用 strstr
。 strstr
在查找给定标记时一直到第一个 [=12=]
字节。显然,二进制数据会有很多,所以搜索在遇到第一个和 returns 'nothing was found'.
后停止
因此,您的代码永远不会退出读取循环,并一直等待更多数据从服务器到达——服务器永远不会发送它。
当然,正确的解决方案是实施发送二进制数据的正确协议。但是,如果由于列出的限制而无法做到这一点,一个半可行的解决方案是用自定义函数替换 strstr
函数,这将越过提供的缓冲区,忽略空终止符(使用大小缓冲区)并查找提供的令牌。如果您的二进制数据中包含令牌,它仍然会中断,但您无能为力。
我有客户端服务器架构,其中我将二进制文件从服务器传输到客户端。
服务器代码:
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] = '[=11=]';
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:]当我尝试发送纯文本文件时,我可以成功发送。只有在发送二进制文件时才会出现问题。 提前致谢。
您的代码失败的原因很简单。您正在将一大块 binary 数据读入您的 buf,然后在此 buf 上调用 strstr
。 strstr
在查找给定标记时一直到第一个 [=12=]
字节。显然,二进制数据会有很多,所以搜索在遇到第一个和 returns 'nothing was found'.
因此,您的代码永远不会退出读取循环,并一直等待更多数据从服务器到达——服务器永远不会发送它。
当然,正确的解决方案是实施发送二进制数据的正确协议。但是,如果由于列出的限制而无法做到这一点,一个半可行的解决方案是用自定义函数替换 strstr
函数,这将越过提供的缓冲区,忽略空终止符(使用大小缓冲区)并查找提供的令牌。如果您的二进制数据中包含令牌,它仍然会中断,但您无能为力。