奇怪的情况:从服务器发送文件

时间:2014-06-23 17:52:23

标签: c

我有代码从服务器发送文件到客户端。 事情是客户端正确接收文件 来自服务器的大小,文件( 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足够长。我觉得奇怪的是接收到了正确的字节数,但图像显示正确一半。

1 个答案:

答案 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() 可以进行部分写入,因此您需要在服务器上编写相同的循环!