我有代码从服务器发送文件到客户端。 事情是客户端正确接收文件 来自服务器的大小,文件( jpeg 图像)也是 在客户端使用正确的文件大小重新创建, 但是当我打开图像时,它会正确显示一半, 一半被腐蚀了。
以下是代码的一些相关部分。知道为什么会这样吗?
服务器:
while(1)
{
printf("Waiting to accept connections \n");
connfd = accept(listenfd, (struct sockaddr*)NULL, NULL);
read_file("/Users/macbookair/Documents/server/server/file1.jpeg", buffer, &length);
// send
write(connfd, &length, 4); // length, 110193 bytes
write(connfd, buffer, length); // file itself
close(connfd);
sleep(1);
}
客户端:
// open file
FILE * ptrMyFile = fopen("/Users/macbookair/Documents/client/client/file1.jpeg","wb");
if(NULL == ptrMyFile)
{
printf("Unable to open file \n");
return 1;
}
int size = 0;
read(sockfd, &size, 4); // read length first
read(sockfd, buffer, size); // then file
printf("fsize %d\n", size);
// create file
fwrite(buffer, size, 1, ptrMyFile);
fclose(ptrMyFile);
buffer
足够长。我觉得奇怪的是接收到了正确的字节数,但图像显示正确一半。
答案 0 :(得分:3)
网络编程与使用本地文件编程不同。
read(sockfd, &size, 4); // read length first
read(sockfd, buffer, size); // then file
您忽略了read()
的返回值 - 最重要的是,它告诉您实际读取了多少字节。由于这是一个网络操作,因此您可能获得的字节数比您要求的少。这意味着只能读取size
的前两个字节,然后您必须再次询问接下来的两个字节。这不太可能,但可能。最有可能的是,如果文件大于几K,文件将被拆分为块。
int read_full(int sock, size_t sz, void *buffer)
{
size_t pos = 0;
while (pos < sz) {
size_t request_amt = sz - pos;
ssize_t result = read(sock, (char *) buffer + pos, request_amt);
if (result < 0) {
// If EINTR, then the read() was interrupted
// In this case, you have to try again
// otherwise, an error occurred
if (errno != EINTR)
return -1;
} else if (result > 0) {
pos += result;
} else {
// unexpected EOF
return -1;
}
}
return 0;
}
实际上,如果您通过TCP连接发送大量数据,它将被分成块并在一段时间内传输。你几乎无法控制这些块的大小。
以下是更正的代码,assert()
用于延迟错误检查:
uint32_t size;
int r;
r = read_full(sockfd, sizeof(size), &size);
assert(r == 0);
void *data = malloc(size);
assert(data != NULL);
r = read_full(sockfd, size, data);
assert(r == 0);
重要说明: write()
/ send()
也可以进行部分写入,因此您需要在服务器上编写相同的循环!