我对 C 中的套接字编程相当陌生,所以下面的代码可能有很多新手错误。我正在尝试制作一个客户端-服务器应用程序,其中服务器将使用 UDP 套接字将文件传输到客户端。客户端和服务器都将在 Linux 主机上运行。这是一项任务,因此必须以这种方式完成。其他客户端-服务器通信可能使用 TCP 套接字,但文件传输必须通过 UDP。该程序适用于小文件,但如果我尝试发送稍大的文件(例如,600 kb 的文本文件),客户端将停止接收数据包,即使服务器会将它们全部发送。这是服务器代码的文件传输部分:
FILE* myFile;
long fileSize, readBytes, sentBytes, sizeCheck;
uint32_t encodedFileSize;
myFile = fopen(fileName, "rb");
if(myFile == NULL)
{
perror("Error when opening file.");
exit(1);
}
fseek(myFile, 0, SEEK_END);
fileSize = ftell(myFile);
encodedFileSize = htonl(fileSize);
rewind(myFile);
sizeCheck = 0;
write(myTCPSocket, &encodedFileSize, sizeof(encodedFileSize));
if(fileSize > 255)
{
while(sizeCheck < fileSize)
{
readBytes = fread(bufferRW, 1, 256, myFile);
sentBytes = sendto(sockfdUDP, bufferRW, readBytes, 0, (struct sockaddr*)&cli_addr, udpAddressSize);
sizeCheck += sentBytes;
}
}
else
{
readBytes = fread(bufferRW, 1, 256, myFile);
sentBytes = sendto(sockfdUDP, bufferRW, readBytes, 0, (struct sockaddr*)&cli_addr, udpAddressSize);
}
if(fileSize == sizeCheck)
{
printf("Success.\n");
}
else
{
printf("Fail.\n");
}
fclose(myFile);
fflush(stdout);
close(sockfdUDP);
如您所见,我使用 TCP 套接字向客户端发送文件大小。这是客户端代码:
FILE *myFile;
long receivedBytes, writtenBytes, sizeCheck;
long fileSize, realFileSize;
char ack2[5] = "Ok";
sockfdUDP = socket(AF_INET, SOCK_DGRAM, 0);
read(socketTCP, &fileSize, sizeof(long));
realFileSize = ntohl(fileSize);
myFile = fopen(fileName, "wb");
if(myFile == NULL)
{
perror("Error when creating file.");
exit(1);
}
sizeCheck = 0;
if((realFileSize) > 255)
{
while(sizeCheck < (realFileSize))
{
receivedBytes = recvfrom(sockfdUDP, bufferRW, 256, 0, (struct sockaddr*)&serv_addr, &serv_addr_size);
writtenBytes = fwrite(bufferRW, 1, receivedBytes, myFile);
fflush(myFile);
sizeCheck += writtenBytes;
}
}
else
{
receivedBytes = recvfrom(sockfdUDP, bufferRW, 256, 0, (struct sockaddr*)&serv_addr, &serv_addr_size);
fwrite(bufferRW, 1, receivedBytes, myFile);
fflush(myFile);
}
if(realFileSize == sizeCheck)
{
printf("Success.");
}
else
{
printf("Fail.");
}
fclose(myFile);
close(sockfdUDP);
“bufferRW”缓冲区最初声明为 char bufferRW[256] 并作为参数传递给函数。其他未声明的变量也是如此。就像我之前说的,服务器(显然)会毫无问题地发送整个文件。但是,客户端将在写入大约 423936 字节后停止接收数据包(这可能因执行而异)。它只会停留在 recvfrom 行,而不读取任何内容。
现在,我确定问题不是由连接错误引起的,因为我正在同一主机上测试这两个进程。realFileSize = ntohl(fileSize);
在你问“256 字节的数据包大小是怎么回事?”之前,如果我使用 1500 的缓冲区大小,有一个奇怪的错误会在客户端线路上引发分段错误。
你能告诉我我在这里错过了什么吗?
编辑:我现在正在尝试使用不同的文件大小。它似乎可以毫无问题地处理大于 256 字节的文件(它在客户端和服务器上都正确地进入和退出 while 循环),但是当文件大于 300 kb 时,客户端将开始出现问题。
编辑2:我刚刚调试了程序。显然,服务器在客户端甚至可以进入其 while 循环之前发送整个文件。
编辑3:我想我知道是什么导致了这个问题。似乎如果服务器在客户端开始读取之前发送了一堆数据包,那么客户端将读取多达 278 个数据包,而不管它们的大小。如果我尝试在客户端开始读取之前发送 279,它将不会读取第 279 个数据包。因此,如果服务器发送数据包的速度足够快,则客户端尚未读取的数据包数量将超过 278 个,并且客户端将无法完成所有数据包的读取。有想法该怎么解决这个吗?