html - 浏览器将C服务器发送过来的图像文件显示为一长串字符

标签 html c sockets ftp

我一直致力于创建一个小型 C 服务器,浏览器可以连接该服务器并对文件发出“GET”请求。我使用典型的“套接字”、“绑定(bind)”、“监听”和“接受”运行服务器的基本结构。然后我使用文件描述符“accept”来调用对客户端的“write”或“send”调用,这会以以下形式发出“GET”请求

    http://ip_address:port/request

我采取的第一步是读取accept_fd(由accept返回)并获取它的第一行,即“GET/request HTTP/1.1\r\n”。然后我用它来创建适当的 HTTP header 来发送文件。

    GET /image_file.gif HTTP/1.1\r\n
    \r\n
    HTTP/1.1 200 OK\r\n
    Content-Type: image.gif\r\n
    Content-Length: 9184\r\n
    \r\n

内容长度是从文件统计信息的 st_size 中获取的,并且与我想要发送的文件相对应,所以这告诉我我正在处理正确的文件。我使用“fopen”和“r”来读取内容,并将“fread”的内容存储到我制作的大字符数组中。最后,我使用“发送”发送了存储文件内容的缓冲区,客户端浏览器接收了它,但显示的内容是一些无法识别的字符(可能是二进制)的乱码。

    GIF89awÄ��ëQiò‹›òŒ›øÅÍìRiæ&Cýðòîn‚õ¨´éC\úÓÙè4Pûâæó™§í`uð}Žö¶Àõ©

这是浏览器上的片段,而不是图像文件。我已经尝试解决这个问题四天了,并尝试了各种方法,例如单独发送 HTTP header 的每个部分而不是一次全部发送,使用“fgetc”和“write”一次发送一个字节的图像文件,但是这些尝试都没有成功。我发送图像文件的操作有问题吗? (还有 html 文件。当我尝试发送它时,所有标签都显示为文本文件,而不是浏览器解释和格式化页面。)

#include <arpa/inet.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>

#define STAT_200 " 200 OK\r\n"
#define STAT_404 " 404 Not Found\r\n"
#define STAT_501 " 501 Not Implemented\r\n"

#define F_DIR "Content-Type: text/directory\r\n"
#define F_GIF "Content-Type: image/gif\r\n"
#define F_HTML "Content-Type: text/html\r\n"
#define F_JPEG "Content-Type: image/jpeg\r\n"
#define F_JPG "Content-Type: image/jpg\r\n"
#define F_TXT "Content-Type: text/plain\r\n"

typedef enum {cgi, gif, html, jpeg, jpg, plain} ext;

ext get_ext(char *file) {
    if (strstr(file, ".cgi") != NULL)
        return cgi;
    if (strstr(file, ".gif") != NULL)
        return gif;
    if (strstr(file, ".html") != NULL)
        return html;
    if (strstr(file, ".jpeg") != NULL)
        return jpeg;
    if (strstr(file, ".jpg") != NULL)
        return jpg;
    if (strstr(file, ".txt") != NULL)
        return plain;
}

void parse(int accept_fd) {
    char *response = (char *) malloc(sizeof(char) * 512);
    char *content = (char *) malloc(sizeof(char) * 512);
    if (read(accept_fd, content, 512) < 0) {
        perror("read error");
        exit(1);
    }

    char *part_end = strstr(content, "\n");
    *(part_end + 1) = 0;     // still has \r\n
    strcat(response, content);
    strcat(response, "\r\n");
    // send(accept_fd, content, strlen(content), MSG_CONFIRM);
    // send(accept_fd, "\r\n", 2, MSG_CONFIRM);     // empty line
    *(part_end - 1) = 0;     // no more \r\n

    char *type = (char *) malloc(sizeof(char) * 256);      // "GET"
    char *request = (char *) malloc(sizeof(char) * 256);   // "/request"
    char *version = (char *) malloc(sizeof(char) * 256);   // "HTTP/x.x"
    strcpy(type, content);
    strcpy(request, strstr(content, "/"));
    strcpy(version, strstr(content, "HTTP"));
    part_end = strstr(type, "/");
    *(part_end - 1) = 0;
    part_end = strstr(request, "HTTP");
    *(part_end - 1) = 0;

    strcat(response, version);
    // send(accept_fd, version, strlen(version), MSG_CONFIRM);     // write the "HTTP/x.x"

    if (strcmp(type, "GET") != 0) { // 501
        strcat(response, STAT_501);
        // send(accept_fd, STAT_501, strlen(STAT_501), MSG_CONFIRM);

    }

    struct stat f_stat;
    int stat_fd;
    char *cwd = (char *) malloc(sizeof(char) * 256);
    char *f_name = (char *) malloc(sizeof(char) * 256);
    if ((cwd = getcwd(cwd, 256)) == NULL) {
        perror("getcwd error");
        exit(1);
    }
    strcpy(f_name, cwd);
    strcat(f_name, request);

    if ((stat_fd = stat(f_name, &f_stat)) < 0) { // 404
        strcat(response, STAT_404);
        // send(accept_fd, STAT_404, strlen(STAT_404), MSG_CONFIRM);

    }

    if S_ISDIR(f_stat.st_mode) { // 200
        strcat(response, STAT_200);
        strcat(response, F_DIR);
        strcat(response, "\r\n"); 
        // send(accept_fd, STAT_200, strlen(STAT_200), MSG_CONFIRM);    // # stat
        // send(accept_fd, "Content-Type: text/directory\r\n", 30, MSG_CONFIRM);
        // send(accept_fd, "\r\n", 2, MSG_CONFIRM);
        write(accept_fd, response, strlen(response));

        int red;
        if ((red = dup2(accept_fd, STDOUT_FILENO)) < 0) {
            perror("dup error");
            exit(1);
        }
        if (execlp("ls", "ls", f_name, NULL) < 0) {
            perror("exec error");
            exit(1);
        }

        close(accept_fd);
        exit(0);
    } else if S_ISREG(f_stat.st_mode) { // 200
        strcat(response, STAT_200);
        // send(accept_fd, STAT_200, strlen(STAT_200), MSG_CONFIRM);    // # stat
        ext f_ext = get_ext(f_name);

        if (f_ext == cgi) {
            int red;
            if ((red = dup2(accept_fd, STDOUT_FILENO)) < 0) {
                perror("dup error");
                exit(1);
            }

            if (execlp(f_name, f_name, NULL) < 0) {
                perror("exec family error");
                exit(1);
            }

            close(accept_fd);
            exit(0);
        } else if (f_ext == gif) {
            strcat(response, F_GIF);
            // send(accept_fd, F_GIF, strlen(F_GIF), MSG_CONFIRM);

            FILE *f_open;
            char *f_cont = (char *) malloc(sizeof(char) * 524288);
            size_t f_size = f_stat.st_size;
            char *con_len = (char *) malloc(sizeof(char) * 64);

            sprintf(con_len, "Content-Length: %d\r\n\r\n", (int) f_size);
            strcat(response, con_len);
            write(accept_fd, response, strlen(response));
            // send(accept_fd, con_len, strlen(con_len), MSG_CONFIRM);  // Content-length: #\r\n

            if ((f_open = fopen(f_name, "r")) == NULL) {
                perror("fopen error");
                exit(1);
            }

            // int i;
            // char ch;
            // for (i = 0; i < f_size; i++) {
            //     ch = fgetc(f_open);
            //     send(accept_fd, &ch, 1, MSG_CONFIRM);
            // }

            fread(f_cont, sizeof(char), f_size, f_open);
            send(accept_fd, f_cont, f_size, MSG_CONFIRM);
            close(accept_fd);
            exit(0);
        } 

这是代码的相关部分,我通过检查字符串长度反复检查是否漏掉了 header 中的\r 或\n,但效果不佳。有这方面经验的人,能指出错误在哪里吗?我是否在任何地方滥用了任何功能?我去掉了它发送 html 文件的部分,因为它之前失败了,所以我主要致力于传输 gif 文件。

最佳答案

事实证明,标题应该从我认为正确的标题的第三行开始。所以它应该看起来像这样:

    HTTP/1.1 200 OK\r\n
    Content-Type: text/html\r\n
    \r\n
    [file content]

关于html - 浏览器将C服务器发送过来的图像文件显示为一长串字符,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23359649/

相关文章:

javascript - 如何在鼠标悬停时从右向左滑动 td 并在鼠标移出时向后滑动

ruby - 防止 ruby​​ 出现 "No buffer space available"错误

javascript - 带有 cookie 的下拉重定向和被更改的能力

javascript - Jquery 找到正确的缓动函数

c - .h 文件中全局变量的链接器错误

c - 不读前进指针

c - 轮询系统调用是否知道远程套接字是关闭还是断开?

php - 如何找到我的 php-fpm.sock?

html - 通过悬停其兄弟来更改元素显示属性

C:函数未返回正确的值