【发布时间】:2022-02-21 21:34:52
【问题描述】:
我目前正在尝试通过套接字 (SOCK_STREAM) 下载/上传文件。以下两个函数是我用来发送和接收数据的。 我目前遇到以下问题: 结果文件有时与源文件的大小不同 这个问题越严重,文件越大。
我很确定我遗漏了一些明显的东西,可能是在我的循环中或确定数据流的结尾。过去一周我尝试了一堆不同的方法/解决方案,这是最接近我得到的工作版本...
感谢您的任何建议和评论,如果我需要提供更多信息,请告诉我
从服务器向客户端发送数据的函数:
void send_file(char *filename, int sock)
{
char data[1024] = {0};
FILE *fp = fopen(filename, "rb");
while (fread(data, sizeof(char), sizeof(data), fp) == 1024) {
if (send(sock, data, sizeof(data), 0) == -1) {
printf("%s%s[-] Error Transmitting File\n\n", KRED, BGHT);
break;
}
bzero(data, sizeof(data));
}
bzero(data, sizeof(data));
strcpy(data, "!EOF!");
send(sock, data, sizeof(data), 0);
bzero(data, sizeof(data));
printf("%s%s[+] Upload Successful\n\n", KGRN, BGHT);
fclose(fp);
}
客户端从服务器接收数据的功能:
void write_file(int sock, char *filepath)
{
FILE *fp;
int n;
char *lastSlash = strrchr(filepath, '\\');
char *filename = lastSlash ? lastSlash +1 : filepath;
char data[1024] = {0};
fp = fopen(filename, "wb");
while (1) {
n = recv(sock, data, sizeof(data), 0);
if (strncmp("!EOF!", data, 5) == 0) {
break;
}
if (n <= 0) {
break;
return;
}
fwrite(data, sizeof(char), sizeof(data), fp);
bzero(data, sizeof(data));
}
fclose(fp);
return;
}
【问题讨论】:
-
在使用
send和recv返回的值时,您需要更加小心。您将recv返回的值存储在n中,但始终将sizeof(data)字符写入目标文件。 -
此代码中的幅度检查所有都需要工作。您正在检查成功/失败,但您需要更加勤奋。例如:除非您的文件以 1K 八位字节的精确倍数结尾,否则最终的部分帧将被忽略(因为
fread将返回结果 send 调用仅检查非直接失败 (-1),但从未验证是否发送准确请求的八位字节数。像这样的事情很重要。 -
'if (strncmp("!EOF!", data, 5) == 0) {' 不,这不能与 SOCK_STREAM 一起可靠地工作。不能保证这 5 个字节会被一次 recv() 调用加载。
-
感谢大家的反馈。关于你的评论 G.M. ,这不应该是问题吗?因为 recv() 返回接收到的字节数,并将其存储在“数据”变量中。关于其他建议,我计划以某种方式对其进行更改,即客户端和服务器首先交换文件的大小(以字节为单位)。由于 send() 和 recv() 都返回字节数,我可以继续发送/接收,直到文件大小被发送/接收。然后 send_file 也将是一个 while(1) 循环,并且 fread()/send() 直到达到文件大小。通过按字节打破循环,strncmp() 将不再是必要的。
标签: c sockets file-transfer