简体   繁体   English

C sockets,jpeg 图像无法正确显示

[英]C sockets, jpeg image not displaying properly

I'm learning about sockets and Im in the process of creating a socket server which can serve html files, as well as images in the jpeg format.我正在学习 sockets 和 Im 在创建可以提供 html 文件以及jpeg格式的图像的套接字服务器的过程中。 Based on other similar posts I've found, I can't deduce what I'm doing wrong.根据我发现的其他类似帖子,我无法推断出我做错了什么。 I use fseek and ftell to get the size of the image, and then I use fread to read those bytes into a malloc 'ed character array, which I then send back.我使用fseekftell来获取图像的大小,然后使用fread将这些字节读入malloc的字符数组,然后将其发回。 What am I doing wrong?我究竟做错了什么?

code for dealing with jpeg files:处理jpeg文件的代码:

else if (!strcmp(getFileExtension(fname), "jpg") || !strcmp(getFileExtension(fname), "jpeg"))
      {
        printf("got a jpeg request\n");
        FILE *fp = fopen(fname, "rb");

        if (fp == NULL)
        {
          perror("Error opening .jpg/.jpeg file");
          status = 500;
          ret = toStr(status);
          statusMessage = " Internal Server Error\n";
          body = "<h1>Server encountered error trying to open jpeg file</h1>";
          mode = html;
          goto shutdown;
        }

        // seek to end of file and get
        // length of the file to read
        fseek(fp, 0, SEEK_END);
        bodySize = ftell(fp);
        printf("file is %d bytes\n", bodySize);

        // seek back to beginning of file
        fseek(fp, 0, SEEK_SET);
        // allocate and read len amt of bytes
        char *data = malloc(bodySize);
        fread(data, sizeof(char), bodySize, fp);
        fclose(fp);

        status = 200;
        ret = toStr(status);
        statusMessage = " OK\n";
        body = data;
        mode = jpeg;
        goto shutdown;
    }

my shutdown code, which simply sets the headers, status codes, etc. The jpeg file data should be within the body variable我的shutdown代码,它只是设置标题、状态代码等。jpeg 文件数据应该在body变量中

    // cleanup and closing
    shutdown:
      // send just the headers first
      size = strlen(header) + strlen(ret) + strlen(statusMessage) + strlen(mode) + 1;
      reply = (char *)malloc(size);
      reply[size - 1] = '\0';
      snprintf(reply, size, "%s%s%s%s", header, ret, statusMessage, mode);
      printf("\n%s\n\n", reply);
      send(new_sd, reply, size, 0);

      // send just body
      if (!strcmp(mode, jpeg)) // jpeg uses bodySize
      {
        printf("body size (%d):\n%s\n", bodySize, body);
        send(new_sd, body, bodySize, 0);
      }
      else // non jpeg uses strlen
      {
        printf("body size (%d):\n%s\n", (int)strlen(body), body);
        send(new_sd, body, strlen(body), 0);
      }

      shutdown(new_sd, SHUT_RDWR);
      close(new_sd);
      exit(0);

Here is my server response to the browser(client):这是我的服务器对浏览器(客户端)的响应:

在此处输入图像描述

Nothing stands out to me in terms of the socket code.就套接字代码而言,我没有什么特别突出的。 Instead of this being a socket (only) issue, maybe it is (also) a protocol issue?这不是一个(唯一的)套接字问题,也许它(也是)一个协议问题? Possibly a non-compliance issue with the HTTP/1.1 ( RFC 7230 +)?可能是 HTTP/1.1( RFC 7230 +)的不合规问题? neither Content-Length nor Transfer-Encoding specified?既没有指定 Content-Length 也没有指定 Transfer-Encoding? bad line endings?行尾不好? (status line would normally end with OK\r\n not OK\n\n) (状态行通常以 OK\r\n not OK\n\n 结尾)

shouldn't use snprintf with %s for binary data like jpeg bytes, I believe %s terminates at null byte (0x00) which makes the binary file corrupt.不应将snprintf%s一起用于 jpeg 字节等二进制数据,我相信%s在 null 字节 (0x00) 处终止,这会使二进制文件损坏。

Also strlen(body) won't work either as strlen will also terminate at null byte (0x00) giving bad length for the jpeg data.同样strlen(body)也不起作用,因为 strlen 也将在 null 字节 (0x00) 终止,从而为 jpeg 数据提供错误的长度。

Try memcpy instead.改用memcpy

Open the file with this mode "rb+"使用此模式"rb+"打开文件

Simple pseudo-code (might not compile)简单的伪代码(可能无法编译)

int jpegDataSize = len;
char* jpegdata = data;
reply_size = strlen(HEADER) + strlen(ret) + strlen(statusMessage) + strlen(mode) + jpegDataSize + 1; //can't use strlen for jpeg because it's binary
reply = (char *)malloc(reply_size);
memcpy(&reply[0], HEADER, strlen(HEADER));
memcpy(&reply[strlen(HEADER)], ret, strlen(ret));
memcpy(&reply[strlen(ret)], statusMessage, strlen(statusMessage));
memcpy(&reply[strlen(statusMessage)], mode, strlen(mode));
memcpy(&reply[strlen(mode)], jpegdata, jpegDataSize); //avoid strlen(jpegdata)
reply[reply_size - 1] = '\0';
printf("\n-------------------------------------\nresponse is (%d): \n%s\n\n", reply_size, reply); //can't use strlen (because jpegdata is binary)
send(new_sd, reply, reply_size, 0); //can't use strlen because jpegdata is binary.
shutdown(new_sd, SHUT_RDWR);
close(new_sd);
exit(0);

Turns out there is no logistical issue to my edited post's code.事实证明,我编辑的帖子代码没有后勤问题。 The problem was that in the shutdown code, when I send the HTTP header reply, I used size as the length for the reply, when I should have used strlen(reply) or size - 1 for send(new_sd, reply, size, 0) .问题是在关机代码中,当我发送 HTTP header 回复时,我使用 size 作为回复的长度,而我应该使用strlen(reply)size - 1 send(new_sd, reply, size, 0) .

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM