【问题标题】:Sending image through sockets not receiving fine通过套接字发送图像未收到正常
【发布时间】:2021-04-10 03:37:40
【问题描述】:

我正在尝试通过sockets 将 jpg 图像从客户端进程发送到服务器。该图像包含二进制数据,因此我想使用readswrites 在低级编程基础上进行。我还以 100 字节的迭代发送图像数据。

这是我完成的代码,它没有按照我的意愿发送图像:

客户

void send_image(char *path, char *filename, int socket) {

    int fd = open(path, O_RDONLY); //I open the file of the image.jpg

    int n = 1;

    while (n > 0) {
        char img_data[100];
        n = read(fd, img_data, 100); //sending 100 bytes of image each iteration till n=0 (end of file)

        if (!n) break;

        int sending = 1;
        write(socket, &sending, sizeof(int)); //Tell the client the image still has data to send

        write(socket, img_data, strlen(img_data));

        usleep(250);
    }

    sending = 0; //Tell the server the image has been fully sent
    write(socket, &sending, sizeof(int));

    close(fd);
}

服务器

void receiving_image(char *path) {

    int receiving = 0;
    int j=0;
    char *image_data = NULL; //Variable to store all the image data

    read(socket, &receiving, sizeof(int)); //Reads that the client is going to send an image

    while (receiving) {

        char data[100]; //Variable that stores partial data (100 bytes) of an image on each iteration 
        read(socket, data, 100);

        image_data = realloc(image_data, (j + strlen(data)) * sizeof(char)); //Readjust the size of the main image data.
      
        for (int i=0; i<(int) strlen(data); i++) {
           
            image_data[j] = data[i]; //copy the partial data of the image to the main variable of the image
            j++;
        }

        j = (int) strlen(image_data); 

        read(socket, &receiving, sizeof(int)); //Read if the image is still sending
    }

    image_to_directory(path, image_data); //Copy image to directory
}

这编译并运行良好,但是当我检查存储图像的服务器端目录时,我可以看到它与客户端发送的图像不同(我通过 md5sum 确认并且哈希值不相等) .

我有什么遗漏吗?

【问题讨论】:

  • strlen(img_data)strlen(data) 是错误的。字符串函数只能用于字符串,不能用于二进制数据。请改用read 的返回值来获取读取/接收的字节数。
  • read() 在出错的情况下返回-1,而不是0。您必须测试&lt;=0
  • 不是你的问题,因为我假设服务器和客户端在类似的机器上运行,但是int 在服务器和客户端上可以有不同的大小。最好使用uint32_t 或类似的东西。
  • @12431234123412341234123 你指的是哪一行? while (n &gt; 0) 没有做到这一点吗?
  • while (n &gt; 0) 为时已晚。如果read 返回-1,代码将继续并在有机会退出循环之前使用read 的结果。实际引用的错误检查是if (!n)

标签: c sockets


【解决方案1】:

您不应该使用strlen 来计算二进制数据长度。它仅适用于终止的 strings(因此得名)。您还有非常不明智的裸读/写调用,这在通过套接字发送数据时会导致灾难。

您似乎一次发送的字节数不会超过 100 个,这在这种情况下有助于开发更可靠的协议。考虑一下:

  1. 第一个八位字节是uint8_t 字节数 N,将在 0..100 内。
  2. 按照字节计数,传输 N 个字节。
  3. 重复 1-2 直到没有剩余字节。
  4. 通过发送单个零八位字节通知服务器 EOF

此处显示了此发件人代码的示例。

void send_image(const char *path, int socket)
{
    int fd = open(path, O_RDONLY); //I open the file of the image.jpg
    if (fd == -1)
        return;

    ssize_t n = 0;
    do
    {
        // note the first octet will prefix the length
        uint8_t img_data[101];
        n = read(fd, img_data+1, 100);
        if (n > 0)
        {
            // you never know  just how many bytes are going to
            // be sent, so setup the frame, but then ensure even
            // piecewise deliver can succeed.
            img_data[0] = (uint8_t)n;
            ssize_t sent = 0;
            size_t pos = 0;
            do
            {
                sent = write(socket, img_data+pos, (n+1)-pos);
                if (sent < 0)
                    break;
                pos += sent;
            } while ( pos < (n+1) && sent > 0);
        }

    } while (n > 0);

    uint8_t done = 0;
    write(socket, &done, sizeof done); // not much we can do if this fails

    close(fd);
}

我没有声称上面的代码甚至可以编译,但这个概念应该是相当明显的。然而,就是这样。显然还有更多可以/应该做的事情(校验和、重启选项等),但这是基本前提。

服务器端可以做类似的事情,我把它留给你作为练习。所有这一切的重点是利用您的读/写调用的返回值。他们在那里是有原因的。如果您发现自己在编写“裸”读或写代码(您没有收集函数的结果并以某种方式利用它),那么您很可能做错了什么。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-07-17
    • 1970-01-01
    • 2013-12-31
    • 2010-10-19
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多