gpt4 book ai didi

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

转载 作者:行者123 更新时间:2023-11-30 14:19:49 25 4
gpt4 key购买 nike

我一直致力于创建一个小型 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/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com