Content-Type not allowed ** image/x-png

本文介绍了Struts2框架中文件上传失败的问题及其解决方法。针对IE浏览器将文件类型误识别为特定MIME类型的问题,通过修改Struts2配置允许这些特定类型,确保文件能够成功上传。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

struts2上传文件时严重过不去,报

Content-Type not allowed: catyIcon "application_xp_terminal.png" "upload__2c2b7695_13a557c978f__8000_00000015.tmp" image/x-png

 

经过查找发现

ie会把 jpgjpeg翻译成image/pjpegpng翻译成image/x-png

 

配置修改如下:

<!-- 上传文件过滤拦截器 -->
<interceptor-ref name="fileUpload"> 
   <param name="allowedTypes">
       <!-- IE浏览器会把 jpg、jpeg翻译成image/pjpeg,png翻译成image/x-png  -->
       image/png,image/gif,image/jpeg,image/jpg,image/bmp,image/ico,image/x-png,image/pjpeg
   </param>
   <param name="maximumSize">500000</param>
</interceptor-ref>


 

 

 

我的全部代码如下,出现了访问index正常但无图片,其他html404./* Copyright(c) Lianzhou International Co.Ltd. * * file threaded_server.c * brief This is a simple muti-threade server. * * author Sun Haoming * version 1.0.0 * date 25Aug14 * * history * \arg 1.0.0, 25Aug14, Sun Haoming, Create the file. */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <sys/socket.h> #include <netinet/in.h> #include <sys/stat.h> #include <fcntl.h> #include <arpa/inet.h> #include <signal.h> #include <sys/wait.h> /**************************************************************************************************/ /* DEFINES */ /**************************************************************************************************/ #define PORT 80 #define BUFFER_SIZE 2048 /**************************************************************************************************/ /* TYPES */ /**************************************************************************************************/ /**************************************************************************************************/ /* EXTERN_PROTOTYPES */ /**************************************************************************************************/ /**************************************************************************************************/ /* LOCAL_PROTOTYPES */ /**************************************************************************************************/ const char *get_content_type(const char *path); void send_response(int client_fd, const char *path); /**************************************************************************************************/ /* VARIABLES */ /**************************************************************************************************/ /**************************************************************************************************/ /* LOCAL_FUNCTIONS */ /**************************************************************************************************/ /* 根据拓展名返回类型 */ const char *get_content_type(const char *path) { const char *ext = strrchr(path, '.'); /* strrchr从末尾查找至. */ if (ext) { if (strcmp(ext, ".html") == 0) return "text/html"; if (strcmp(ext, ".css") == 0) return "text/css"; if (strcmp(ext, ".js") == 0) return "application/javascript"; if (strcmp(ext, ".png") == 0) return "image/png"; if (strcmp(ext, ".jpg") == 0) return "image/jpeg"; } return "application/octet-stream"; /*默认返回二进制流*/ } /* 发送HTTP响应给客户端 */ void send_response(int client_fd, const char *path) { char header[BUFFER_SIZE]; /*响应头buffer*/ char buffer[BUFFER_SIZE]; /*内容buffer*/ struct stat st; /*文件状态*/ /* 文件不存在 */ if (stat(path, &st) == -1) { printf("该文件未找到:%s\n", path); /* 404 文件头 */ snprintf(header, BUFFER_SIZE, "HTTP/1.1 404 Not Found\r\n" "Content-Type: text/html\r\n" "\r\n" "<h1>404 Not Found</h1>"); send(client_fd, header, strlen(header), 0); return; } /*读取文件*/ int fd = open(path, O_RDONLY); if (fd < 0) { printf("打开该文件失败: %s\n", path); return; } /* 200 OK 文件头 */ snprintf(header, BUFFER_SIZE, "HTTP/1.1 200 OK\r\n" "Content-Type: %s\r\n" "Content-Length: %ld\r\n" "\r\n", get_content_type(path), st.st_size); send(client_fd, header, strlen(header), 0); printf("发送文件: %s (大小: %ld 字节)\n", path, st.st_size); /*发送给客户端*/ ssize_t bytes_read; while ((bytes_read = read(fd, buffer, BUFFER_SIZE)) > 0) { send(client_fd, buffer, bytes_read, 0); } close(fd); } /*客户端请求线程*/ void handle_client(int client_fd) { /*直接接受int*/ char buffer[BUFFER_SIZE]; char path[BUFFER_SIZE] = "./"; /* 默认./ */ char method[16] = {0}; /*存储请求方法*/ int content_length = 0; /* POST内容长度*/ /*读取客户端请求*/ ssize_t bytes_read = read(client_fd, buffer, BUFFER_SIZE - 1); if (bytes_read <= 0) { printf("读取客户端请求失败\n"); close(client_fd); return; } buffer[bytes_read] = '\0'; /* 获取客户端IP */ struct sockaddr_in addr;/*地址结构*/ socklen_t addr_len = sizeof(addr);/*地址长度*/ getpeername(client_fd, (struct sockaddr*)&addr, &addr_len);/*获取当前socket的对端地址*/ char client_ip[INET_ADDRSTRLEN];/*存储IP*/ inet_ntop(AF_INET, &addr.sin_addr, client_ip, sizeof(client_ip));/*将二进制IP转为字符串*/ printf("收到来自 %s 的请求:\n%.*s\n", client_ip, (int)bytes_read, buffer); /* 解析请求方法 */ sscanf(buffer, "%s %s", method, path + 2); /* path+2跳过./ */ /* 获取GET请求 */ if (strcmp(method, "GET") == 0) { if (strncmp(buffer, "GET ", 4) == 0) { char *start = buffer + 4; char *end = strchr(start, ' '); /* 查找空格结束 */ if (end) { *end = '\0'; /* 根目录 */ if (strcmp(start, "/") == 0) { strcat(path, "Index.html"); } else { /* 拼接根目录+路径 */ strncat(path, start, BUFFER_SIZE - strlen(path) - 1); } } } send_response(client_fd, path); } // 处理POST请求 (新增) else if (strcmp(method, "POST") == 0) { char *body_start = strstr(buffer, "\r\n\r\n"); if (body_start) { body_start += 4; // 跳过空行 char *content_len_ptr = strstr(buffer, "Content-Length: "); if (content_len_ptr) { sscanf(content_len_ptr, "Content-Length: %d", &content_length); } // 处理表单提交示例 if (strstr(path, "/submit") != NULL) { char response[BUFFER_SIZE]; snprintf(response, BUFFER_SIZE, "HTTP/1.1 200 OK\r\n" "Content-Type: text/html\r\n\r\n" "<html><body>" "<h1>表单已提交</h1>" "<p>收到数据: %.*s</p>" "</body></html>", content_length, body_start); send(client_fd, response, strlen(response), 0); printf("处理POST数据: %.*s\n", content_length, body_start); } } } // 其他请求方法处理 else { const char *resp = "HTTP/1.1 405 Method Not Allowed\r\n\r\n"; send(client_fd, resp, strlen(resp), 0); } close(client_fd); printf("请求处理完成\n"); return; } int main() { signal(SIGPIPE, SIG_IGN); /*忽略SIGPIPE管道信号*/ printf("Web服务器启动,监听端口 %d \n", PORT); /*创建TCP套接字*/ int server_fd = socket(AF_INET, SOCK_STREAM, 0); if (server_fd < 0) { perror("创建套接字失败"); exit(EXIT_FAILURE); } /*允许快速重启,地址重用*/ int opt = 1; setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)); /*配置服务器地址结构*/ struct sockaddr_in addr = { .sin_family = AF_INET, .sin_port = htons(PORT), .sin_addr.s_addr = INADDR_ANY }; /* 绑定 */ if (bind(server_fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) { perror("绑定端口失败"); exit(EXIT_FAILURE); } /* 监听 */ if (listen(server_fd, 10) < 0) { perror("监听失败"); exit(EXIT_FAILURE); } printf("服务器已启动\n"); /* 持续接收客户端连接*/ while (1) { struct sockaddr_in client_addr; socklen_t client_len = sizeof(client_addr); /*阻塞等到下一个客户端连接*/ int client_fd = accept(server_fd, (struct sockaddr*)&client_addr, &client_len); if (client_fd < 0) { perror("接受连接失败"); continue; } /*非阻塞的回收僵尸进程,WNOHANG无子进程退出立即返回*/ while (waitpid(-1, NULL, WNOHANG) > 0); /*创建子进程处理客户端请求*/ pid_t pid = fork(); if (pid < 0) { perror("fork失败"); close(client_fd); } else if (pid == 0) { close(server_fd);/*子进程不用监听服务端*/ handle_client(client_fd); /*子进程处理客户端请求*/ exit(0); } else { close(client_fd); /*父进程不要客户端*/ } } close(server_fd); return 0; }
08-16
/* *\file server.c *\brief This code is a function for socket tcp server. *\author Chen Xinyi <chenxinyi1@tp-link.com.hk> *\version 1.0.0 *\date 6/8/2025 *\history \arg 1.0.0 6/8/2025, chenxinyi, Create file. */ /**************************************************************************************************/ /*****************************************INCLUDE_FILES********************************************/ /**************************************************************************************************/ #include <unistd.h> #include <sys/types.h> #include <sys/socket.h> #include <netdb.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <ctype.h> #include <errno.h> #include <malloc.h> #include <netinet/in.h> #include <arpa/inet.h> #include <sys/ioctl.h> #include <stdarg.h> #include <fcntl.h> #include <fcntl.h> /* 涉及到多进程操作时加入如下语句: */ #include <sys/wait.h> #include <sys/ipc.h> #include <sys/shm.h> #include <signal.h> /* 涉及到多线程操作时加入如下语句: */ #include <pthread.h> #include <sys/poll.h> /**************************************************************************************************/ /********************************************DEFINES***********************************************/ /**************************************************************************************************/ #define PORT 80 #define BUFFER_SIZE 1024 /**************************************************************************************************/ /********************************************FUNCTION**********************************************/ /**************************************************************************************************/ /* void send_error(int client_fd, int status_num, const char* status_msg, const char* edition) { char response[1024]; // snprintf 将格式化的数据写入指定的字符串缓冲区,若字符串长度超了,输出被截断,并在最后添加空字符 int length = snprintf(response, sizeof(response), "%s %s %d \r\n" "server: %d\r\n" "Content-Type: image/svg+xml\r\n" "<html>\r\n" "<head>\r\n" "<title>error page</title>\n" "</head>\n" "<body>\r\n" "<h1>%d</h1>\r\n" "<%s>\r\n" "</body>\r\n" "</html>\r\n", edition, status_msg, status_num, client_fd, status_num, status_msg); send(client_fd, response, length, 0); } */ /**************************************************************************************************/ /********************************************FUNCTION**********************************************/ /**************************************************************************************************/ // 文件类型映射 const char* get_mime_type(const char *path) { const char *ext = strrchr(path, '.'); if (!ext) return "text/plain"; if (strcmp(ext, ".html") == 0) return "text/html"; if (strcmp(ext, ".css") == 0) return "text/css"; if (strcmp(ext, ".js") == 0) return "application/javascript"; if (strcmp(ext, ".jpg") == 0 || strcmp(ext, ".jpeg") == 0) return "image/jpeg"; if (strcmp(ext, ".png") == 0) return "image/png"; return "application/octet-stream"; } /**************************************************************************************************/ /********************************************FUNCTION**********************************************/ /**************************************************************************************************/ /* 用来从server获取数据,因此需要解析GET请求的具体资源类型 */ void handle_get(int client_fd, char* path) { char uri[BUFFER_SIZE], http_version[BUFFER_SIZE]; sscanf(path, "%s %s", uri, http_version); char *response = "HTTP/1.1 200 OK\r\n" "Content-Type: Text/html\r\n" "\r\n" "<html><body><h1>open</h1></body></html>"; /* 当请求是GET,需要读取文件并且返回,调用open等与文件系统交互,同时处理404错误和目录遍历问题 */ /* 1.打开文件 */ FILE* file = fopen(uri, "rb"); if (!file) { printf("无法打开文件: %s (%s)\n", uri, strerror(errno)); char *response_er = "HTTP/1.1 500 Internal Server Error\r\n" "\r\n"; send(client_fd, response_er, strlen(response_er), 0); return; } // 构建文件路径 char full_path[512]; if (strcmp(path, "/") == 0) { snprintf(full_path, sizeof(full_path), "%s/Index.html", "./web"); } else { snprintf(full_path, sizeof(full_path), "%s%s", "./web", path); } // 获取文件大小 fseek(file, 0, SEEK_END); long size = ftell(file); fseek(file, 0, SEEK_SET); // 发送HTTP头 char header[BUFFER_SIZE]; snprintf(header, sizeof(header), "HTTP/1.1 200 OK\r\nContent-Type: %s\r\nContent-Length: %ld\r\nConnection: close\r\n\r\n", get_mime_type(path), size); send(client_fd, header, strlen(header), 0); // 发送文件内容 char buffer[BUFFER_SIZE]; size_t bytes_read; while ((bytes_read = fread(buffer, 1, sizeof(buffer), file)) > 0) { send(client_fd, buffer, bytes_read, 0); } fclose(file); } /**************************************************************************************************/ /********************************************FUNCTION**********************************************/ /**************************************************************************************************/ char *get_header_value(char *header, char *key) { char *key_pos = strstr(header, key); if (key_pos == NULL) { return NULL; } /* strchr搜索在另字符串中第一次出现,默认false,如果为true则返回search参数第一次出现之前的字符串部分 */ char *value_pos = strchr(key_pos, ':'); if(value_pos == NULL) { return NULL; } value_pos++; while (*value_pos == ' ') { value_pos++; } char *end_pos = strstr(value_pos, "\r\n"); if(end_pos == NULL) { return NULL; } *end_pos = '\0'; return value_pos; } /**************************************************************************************************/ /********************************************FUNCTION**********************************************/ /**************************************************************************************************/ /* 修改server数据,数据放在request里: * post产生两个TCP包,浏览器先发送header,100后,浏览器再发送打压,返回200 */ void handle_post(int client_fd, char* path) { char *header = {0}; char *body = {0}; /* 寻找有无Length头 */ header = strstr(path, "Content-Length"); if (header == NULL) { return; } /* atoi把参数str所指向的字符串转换为一个整数 */ int content_length = atoi(get_header_value(header, "Content-Length")); body = strstr(path, "\r\n\r\n")+4; if (body == NULL) { return; } printf("POST request body: %.*s\n", content_length, body); char *response = "HTTP/1.1 200 OK\r\n" "Content-Type: Text/plain\r\n" "\r\n" "success!"; send(client_fd, response, strlen(response), 0); } /**************************************************************************************************/ /********************************************FUNCTION**********************************************/ /**************************************************************************************************/ /* 解读http报文 */ void handle_http_request(int client_fd) { char request[BUFFER_SIZE] = {0}; /* 1.读取浏览器请求*/ //read(client_fd, request, BUFFER_SIZE-1); ssize_t bytes_read = recv(client_fd, request, BUFFER_SIZE - 1, 0); if (bytes_read <= 0) { if (bytes_read == 0) { printf("客户端关闭了连接\n"); } else { perror("接收请求失败"); } return; } request[bytes_read] = '\0'; // 确保字符串结束 printf("------------------ 收到请求 ------------------%s\n",request); /* 2.提取请求信息(方法、路径) */ /* strtok将字符串分割,并修改传入的字符串将分隔符替为\0, 后续调用时,传NULL,表示继续分割同一个字符串 */ char* method = strtok(request, " "); char* path = strtok(NULL, ""); if (strcmp(method, "GET") == 0) { handle_get(client_fd, path); } else if (strcmp(method, "POST") == 0) { handle_post(client_fd, path); } else { char *response = "HTTP/1.1 405 Method Not Allowed\r\n" "Content-Length: 0\r\n" "\r\n"; send(client_fd, response, strlen(response), 0); } close(client_fd); return; } /**************************************************************************************************/ /********************************************FUNCTION**********************************************/ /**************************************************************************************************/ int main() { /* 1.创建socket文件描述符:创建套接字成功时返回一个非负整数 */ int server_fd; if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) { perror("socket failed"); exit(EXIT_FAILURE); } /* 声明serv_addr变量, sockaddr_in定义在头文件<arpa/inet.h>中,专用于互联网环境下的套接字地址格式 */ /* struct sockaddr_in { short int sin_family; 地址族 unsigned short int sin_port;端口号 struct in_addr sin_addr; Internet地址 unsigned char sin_zero[8]; 与struct sockaddr一样的长度 }; */ /* 2.配置服务器地址 */ struct sockaddr_in serv_addr = {0}; memset(&serv_addr, 0, sizeof(serv_addr)); /* 使用IPV4地址 */ serv_addr.sin_family = AF_INET; /* 设置IP,监听本地所有网口,仅服务端可用INADDR_ANY */ serv_addr.sin_addr.s_addr = INADDR_ANY; /* 端口!需要转化为网络字节序再赋给socket */ serv_addr.sin_port = htons(PORT); /* 3.绑定server_fd到端口,文件描述符绑定到指定地址和端口 */ /* bind(socket描述字,要绑定给描述字的协议地址,对应地址长度)函数把一个地址组中特定地址赋给socket */ /* 绑定成功之后,如果客户端试图连接指定地址和端口建立TCP连接,系统就会转给server_fd这个文件处理 */ if (bind(server_fd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) { perror("bind failed"); exit(EXIT_FAILURE); } /* 4.进入监听状态 如果客户端用connct()发出请求,服务器就会监听到 */ /* int listen(int sockfd, int backlog) 监听的socket描述字,相应socket可以排队的最大连接个数 */ /* 监听server_fd,就是鉴定这个地址和端口 */ if (listen(server_fd, 3) < 0) { perror("listen failed"); exit(EXIT_FAILURE); } printf("TCP服务器已启动, 监听端口: %d\n", PORT); /* server_fd就是用于监听的,client_fd采用来进行实际的数据传输 */ int client_fd; struct sockaddr_in client_addr = {0}; socklen_t clnt_addr_size = sizeof(client_addr); /* 循环处理每个连接 */ while (1) { /* 接受客户端连接,返回新连接的套接字描述符 */ /* 如果客户端连接成功,client_fd这个套接字描述符代表的就是这个客户端连接,通过对这个套接字的读写来接收和发送数据 */ if ((client_fd = accept(server_fd, (struct sockaddr *)&client_addr, &clnt_addr_size)) < 0) { perror("accept failed"); continue; } printf("Connection established with new client\n"); handle_http_request(client_fd); /* 不断读取客户端发送的数据,直至连接关闭 */ /* 使用pthread_create创建新线程,设计线程创建、同步机制如互斥锁、条件变量等,使用epoll等高效IO模型 */ close(client_fd); } /* 关闭套接字 */ close(client_fd); close(server_fd); return 0; } 帮我看看问题吧
08-09
请帮我填充开发报告。1. 前言 1.1. 项目简要说明 本项目。 在此简要描述项目背景、需求。可参考立项报告或软件开发任务书,进行概括或补充。项目一般对应机型,如WR741N 1.0。 1.2. 任务概述 说明本任务是项目的全部,还是项目的子模块,是新设计模块,还是对原有模块或代码的修改,等等。任务一般对应模块,如WR741N 1.0的防火墙模块。 1.3. 可用资源 可选,说明不需要重新开发的可利用资源,如现成的模块、控件和软件等。 1.4. 术语定义 列举本文所用的专门术语的定义和英文缩写词的原文及解释。注意,术语之间如有引用关系,被引用者列在前面。 1.5. 参考资料 参考资料指概要设计中引用的开发流程文档或规范,或者有利于加深概要设计理解的资料(读者必须能容易获得)。请在下面列出资料,并给出这些文件资料的标题、作者、编号、版本号、发表日期和出版单位或资料的来源:  经批准的开发文档;  引用的软件开发标准和规范;  说明本文档中引用的其他文件和资料。 2. 需求分析 强烈鼓励单独撰写需求分析文档。 如果没有单独的需求分析文档,在此分层次对需求进行分析。主要是分析以下方面:  界定系统的对外提供的功能(将对应于概要设计中的模块接口或系统界面);  详细的功能项及功能的分类(将对应于概要设计中的模块划分);  功能分类之间的关系(将对应于概要设计中的模块关系);  功能的作用或流程(将对应于概要设计中的模块内部建模);  提供上述功能时需要达到的性能(将影响概要设计中协议、算法等的选择)。 3. 原理概述 本章分析任务的重点原理,如协议、算法等等。如果需要原理概述,本章为概要设计的重点内容。不需要时删除本章。 注意,原理不是实现的结果,而是实现的依据。如果属于协议设计,要说明为什么要这样设计。移植型的任务,原理着重讲移植要注意的平台差异。修改/增加型的任务,原理着重讲修改或增加的部分。 以下小节如果内容较多,请扩展成独立的一章。 3.1. 协议分析(或设计) 本节分析要使用并实现的协议标准(如PPTP协议),或根据需求设计新协议(如防火墙产品用户认证协议)及设计的出发点和思路。不需要时删除本节。 3.1.1. 协议描述 概述协议实现的目标、原理等。 3.1.2. 协议数据格式 协议使用的数据格式,如网络网络协议的帧格式。 3.1.3. 协议描述 描述协议的以下方面:  协议收发包的方式,如使用socket还是其他接口,是否阻塞,等等。  协议模块与任务(或线程)的关系,如果涉及多任务,说明任务间通信的方式。  双方或多方进行协议通信的互交图、状态图或其他形式的描述。 3.2. 重要算法与数据结构 本节分析要实现的重要算法(如防火墙项目策略模块查找算法设计)、相关数据定义以及算法依赖的数据结构。 4. 系统构架描述 4.1. 概述 概要地叙述模块划分的原则,如通过对需求进行分析得到几类功能,从而相应地将系统分成几个模块。 注意:这里说的模块,指的是本任务之下划分的模块。如果本任务是产品的一个模块,那么这里的模块实际上是产品模块中的子模块。 4.2. 模块结构 辅于模块结构图等形式,表述模块的划分情况(根据、命名、结果)和模块之间的关系,说明模块的相互关系是本节的重点。 说明:这是设计中对复杂系统“分而治之”的过程。注意“分”的合理性,并通过对模块关系的分析,保持系统的功能完整性。 4.3. 模块描述和建模 逐一说明每个模块的基本情况,包括:模块自身的功能;对项目以内或以外其他模块提供的功能;模块的简要流程或算法的名称;模块的重要性;等等。 如果划分的模块有比较复杂的(如存在多个对象),则对模块进行建模:  首先介绍模块及其包括对象的功能和属性。  其次可以描述对象之间的关系,如成绩管理模块中,学生、成绩、班级等对象的关系。  然后可以描述模块的主要流程,如加密过程。 5. 任务(或进程/线程)设计 必须描述的内容。 如果本任务需要单独的任务(或进程/线程)或采用多任务(进程/线程)、线程池等,在本章描述任务或进程/线程的使用设计(包括它们与模块的关系)。即使没有增加新的任务或进程/线程,也要描述代码的运行方式。如果涉及中断处理的,同样要说明。 5.1. 原因 说明使用新的任务(或进程/线程)、采用多个任务(或进程/线程)或线程池的原因。 5.2. 任务(或进程/线程)内部流程 依次说明每个任务/进程/线程实现什么流程,如果前面已经有流程,指出对应关系即可。 5.3. 任务(或进程/线程)间通信 每两个需要进行信息交互的任务,都要说明通信的信息内容、交互方式。 6. 内存管理 如果需要内存的特别使用和管理,在本章说明,否则删除本章。 6.1. 说明 说明哪些数据类型需要进行特别管理,如:  作用  被哪些模块、函数、任务(或线程)使用 6.2. 设计 如何对内存进行管理,包括但不限于以下内容:  是否要互斥和/或同步  是否要反复申请、释放  内存维护方式 7. 出错处理 可选。复杂项目需要统一的出错处理,否则删除本节。 8. 用户界面概要设计 可选,如有用户界面(包括GUI和CLI),在本章描述界面设计,否则删除本章节。先说明界面的关系,再对每个主要界面进行说明。 8.1. 界面组织 说明界面设计的指导原则。用图表描述不同界面间的组织关系。 8.2. 界面设计 对主要界面进行设计。 9. 接口概要设计 本章的接口指提供给其他模块调用的接口。如果需要给其他模块或对外提供接口,在本章说明,否则删除本章。 接口的设计要与使用模块的设计人进行协商。要注意完整性(能实现所有需要的功能)和易用性(不能让使用者需要经过复杂的准备或步骤才能调用)。 9.1. 概述 说明接口设计思想。要说明是否达到完整性,给出充分理由。 9.2. 接口分类与功能 接口设计,包括接口的分类及功能说明,大致的输入和输出,等等。如果接口提供给不同模块使用,或接口分不同的功能,要进行分类并说明。 如果一些对外功能需要调用若干个接口的组合才能实际,请说明。 10. 开发环境、测试环境及部署环境 10.1. 开发环境 指明开发所需环境,如:  硬件(交叉编译时包括宿主机和目标机)  OS(交叉编译时包括宿主机和目标机)  编译器、集成开发环境  其他 10.2. 测试环境 测试所需环境。如网络拓扑、测试设备等。 10.3. 部署环境 开发成果的部署环境。包括需要使用的硬件、软件、网络环境等。注意部署的层次性,如DHCP Client模块,部署到vxWorks平台的无线路由器(在WAN口使用),再描述无线路由器的部署。 《简要描述即可》项目具体如下,分别使用多线程,多进程,IO多路复用实现一个简单的web server(端口80)承载附件的web。对比这三种实现方式各自的优缺点。 下面给出了process多进程服务器的代码样例,其余两个改动不大。/* Copyright(c) Lianzhou International Co.Ltd. * * file process_server.c * brief This is a simple muti-process server. * * author Sun Haoming * version 1.0.0 * date 25Aug14 * * history * \arg 1.0.0, 25Aug14, Sun Haoming, Create the file. */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <sys/socket.h> #include <netinet/in.h> #include <sys/stat.h> #include <fcntl.h> #include <arpa/inet.h> #include <signal.h> #include <sys/wait.h> /**************************************************************************************************/ /* DEFINES */ /**************************************************************************************************/ #define PORT 80 #define BUFFER_SIZE 2048 /**************************************************************************************************/ /* TYPES */ /**************************************************************************************************/ /**************************************************************************************************/ /* EXTERN_PROTOTYPES */ /**************************************************************************************************/ /**************************************************************************************************/ /* LOCAL_PROTOTYPES */ /**************************************************************************************************/ const char *get_content_type(const char *path); void send_response(int client_fd, const char *path); /**************************************************************************************************/ /* VARIABLES */ /**************************************************************************************************/ /**************************************************************************************************/ /* LOCAL_FUNCTIONS */ /**************************************************************************************************/ /* 根据拓展名返回类型 */ const char *get_content_type(const char *path) { const char *ext = strrchr(path, '.'); /* strrchr从末尾查找至. */ if (ext) { if (strcmp(ext, ".html") == 0) return "text/html"; if (strcmp(ext, ".css") == 0) return "text/css"; if (strcmp(ext, ".js") == 0) return "application/javascript"; if (strcmp(ext, ".png") == 0) return "image/png"; if (strcmp(ext, ".jpg") == 0) return "image/jpeg"; } return "application/octet-stream"; /*默认返回二进制流*/ } /* 发送HTTP响应给客户端 */ void send_response(int client_fd, const char *path) { char header[BUFFER_SIZE]; /*响应头buffer*/ char buffer[BUFFER_SIZE]; /*内容buffer*/ struct stat st; /*文件状态*/ /* 文件不存在 */ if (stat(path, &st) == -1) { printf("该文件未找到:%s\n", path); /* 404 文件头 */ snprintf(header, BUFFER_SIZE, "HTTP/1.1 404 Not Found\r\n" "Content-Type: text/html\r\n" "\r\n" "<h1>404 Not Found</h1>"); send(client_fd, header, strlen(header), 0); return; } /*读取文件*/ int fd = open(path, O_RDONLY); if (fd < 0) { printf("打开该文件失败: %s\n", path); return; } /* 200 OK 文件头 */ snprintf(header, BUFFER_SIZE, "HTTP/1.1 200 OK\r\n" "Content-Type: %s\r\n" "Content-Length: %ld\r\n" "\r\n", get_content_type(path), st.st_size); send(client_fd, header, strlen(header), 0); printf("发送文件: %s (大小: %ld 字节)\n", path, st.st_size); /*发送给客户端*/ ssize_t bytes_read; while ((bytes_read = read(fd, buffer, BUFFER_SIZE)) > 0) { send(client_fd, buffer, bytes_read, 0); } close(fd); } /*客户端请求线程*/ void handle_client(int client_fd) { /*直接接受int*/ char buffer[BUFFER_SIZE]; char path[BUFFER_SIZE] = "."; /* 默认./ */ char method[16] = {0}; /*存储请求方法*/ int content_length = 0; /* POST内容长度*/ char request_path[BUFFER_SIZE] = {0}; /* 存储原始请求路径*/ /*读取客户端请求*/ ssize_t bytes_read = read(client_fd, buffer, BUFFER_SIZE - 1); if (bytes_read <= 0) { printf("读取客户端请求失败\n"); close(client_fd); return; } buffer[bytes_read] = '\0'; /* 获取客户端IP */ struct sockaddr_in addr;/*地址结构*/ socklen_t addr_len = sizeof(addr);/*地址长度*/ getpeername(client_fd, (struct sockaddr*)&addr, &addr_len);/*获取当前socket的对端地址*/ char client_ip[INET_ADDRSTRLEN];/*存储IP*/ inet_ntop(AF_INET, &addr.sin_addr, client_ip, sizeof(client_ip));/*将二进制IP转为字符串*/ printf("收到来自 %s 的请求:\n%.*s\n", client_ip, (int)bytes_read, buffer); /* 解析请求方法 */ sscanf(buffer, "%s %s", method, request_path); /* 获取GET请求 */ if (strcmp(method, "GET") == 0) { /* 根目录请求*/ if (strcmp(request_path, "/") == 0) { strcat(path, "/Index.html"); } else { strncat(path, request_path, BUFFER_SIZE - strlen(path) - 1); } send_response(client_fd, path); } /* 处理POST请求 */ else if (strcmp(method, "POST") == 0) { char *body_start = strstr(buffer, "\r\n\r\n"); if (body_start) { body_start += 4; char *content_len_ptr = strstr(buffer, "Content-Length: "); if (content_len_ptr) { sscanf(content_len_ptr, "Content-Length: %d", &content_length); } /*处理表单提交*/ if (strstr(path, "/submit") != NULL) { char response[BUFFER_SIZE]; snprintf(response, BUFFER_SIZE, "HTTP/1.1 200 OK\r\n" "Content-Type: text/html\r\n\r\n" "<html><body>" "<h1>表单已提交</h1>" "<p>收到数据: %.*s</p>" "</body></html>", content_length, body_start); send(client_fd, response, strlen(response), 0); printf("处理POST数据: %.*s\n", content_length, body_start); } } } /* 其他请求方法*/ else { const char *resp = "HTTP/1.1 405 Method Not Allowed\r\n\r\n"; send(client_fd, resp, strlen(resp), 0); } close(client_fd); printf("请求处理完成\n"); return; } int main() { signal(SIGPIPE, SIG_IGN); /*忽略SIGPIPE管道信号*/ printf("Web服务器启动,监听端口 %d \n", PORT); /*创建TCP套接字*/ int server_fd = socket(AF_INET, SOCK_STREAM, 0); if (server_fd < 0) { perror("创建套接字失败"); exit(EXIT_FAILURE); } /*允许快速重启,地址重用*/ int opt = 1; setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)); /*配置服务器地址结构*/ struct sockaddr_in addr = { .sin_family = AF_INET, .sin_port = htons(PORT), .sin_addr.s_addr = INADDR_ANY }; /* 绑定 */ if (bind(server_fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) { perror("绑定端口失败"); exit(EXIT_FAILURE); } /* 监听 */ if (listen(server_fd, 10) < 0) { perror("监听失败"); exit(EXIT_FAILURE); } printf("服务器已启动\n"); /* 持续接收客户端连接*/ while (1) { struct sockaddr_in client_addr; socklen_t client_len = sizeof(client_addr); /*阻塞等到下一个客户端连接*/ int client_fd = accept(server_fd, (struct sockaddr*)&client_addr, &client_len); if (client_fd < 0) { perror("接受连接失败"); continue; } /*非阻塞的回收僵尸进程,WNOHANG无子进程退出立即返回*/ while (waitpid(-1, NULL, WNOHANG) > 0); /*创建子进程处理客户端请求*/ pid_t pid = fork(); if (pid < 0) { perror("fork失败"); close(client_fd); } else if (pid == 0) { close(server_fd);/*子进程不用监听服务端*/ handle_client(client_fd); /*子进程处理客户端请求*/ exit(0); } else { close(client_fd); /*父进程不要客户端*/ } } close(server_fd); return 0; }
最新发布
08-16
#include <stdio.h> #include <sys/socket.h> #include <sys/types.h> #include <netinet/in.h> #include <netinet/tcp.h> #include <arpa/inet.h> #include <unistd.h> #include <ctype.h> #include <strings.h> #include <string.h> #include <sys/stat.h> #include <pthread.h> #include <sys/wait.h> #include <stdlib.h> #include <dirent.h> #include <time.h> #define ISspace(x) isspace((int)(x)) #define SERVER_STRING "Server: jdbhttpd/0.2.0\r\n" // 函数声明 void* accept_request(void *); void bad_request(int); void cat(int, FILE *); void cannot_execute(int); void error_die(const char *); int get_line(int, char *, int); void headers(int, const char *, const char *); void not_found(int); void serve_file(int, const char *); int startup(unsigned short *); void unimplemented(int); void forbidden(int); void serve_directory(int, const char *); void url_decode(char *, const char *); const char *get_mime_type(const char *); void log_request(const char *, const char *, int); void set_socket_timeout(int, int); /**********************************************************************/ /* 处理客户端请求 */ /**********************************************************************/ void* accept_request(void *pclient) { int client = *(int*)pclient; free(pclient); set_socket_timeout(client, 2); char buf[65536]; int numchars; char method[255]; char url[255]; char path[1024]; // 增加路径长度 char decoded_url[1024]; // 存储解码后的URL size_t i, j; struct stat st; // 获取请求的第一行 numchars = get_line(client, buf, sizeof(buf)); i = 0; j = 0; while (!ISspace(buf[j]) && (i < sizeof(method) - 1)) { method[i] = buf[j]; i++; j++; } method[i] = '\0'; // 只支持GET和POST方法 if (strcasecmp(method, "GET") && strcasecmp(method, "POST") && strcasecmp(method, "OPTIONS")) { unimplemented(client); return NULL; } // 读取URL i = 0; while (ISspace(buf[j]) && (j < sizeof(buf))) j++; while (!ISspace(buf[j]) && (i < sizeof(url) - 1) && (j < sizeof(buf))) { url[i] = buf[j]; i++; j++; } url[i] = '\0'; // URL解码 url_decode(decoded_url, url); // 记录请求日志 log_request(method, decoded_url, client); // 构建文件路径(使用当前目录) sprintf(path, "web%s", decoded_url); // 防止路径遍历攻击 if (strstr(path, "..")) { forbidden(client); close(client); return NULL; } // 处理目录请求 if (path[strlen(path) - 1] == '/') strcat(path, "Index.html"); // 检查文件/目录是否存在 if (stat(path, &st) == -1) { // 检查是否存在.html扩展名文件 char alt_path[1024]; sprintf(alt_path, "%s.html", path); if (stat(alt_path, &st) == 0) { strcpy(path, alt_path); } else { /* 跳过剩余头部 */ while ((numchars > 0) && strcmp("\n", buf)) numchars = get_line(client, buf, sizeof(buf)); not_found(client); close(client); return NULL; } } // 如果是目录 if ((st.st_mode & S_IFMT) == S_IFDIR) { // 检查目录中是否有index.html char index_path[1024]; sprintf(index_path, "%s/Index.html", path); if (stat(index_path, &st) == 0) { strcpy(path, index_path); } else { // 显示目录列表 serve_directory(client, path); close(client); return NULL; } } serve_file(client, path); close(client); return NULL; } /**********************************************************************/ /* URL解码 */ /**********************************************************************/ void url_decode(char *dest, const char *src) { char *p = dest; while (*src) { if (*src == '%') { if (src[1] && src[2]) { char hex[3] = {src[1], src[2], '\0'}; *p++ = (char)strtol(hex, NULL, 16); src += 3; } else { *p++ = *src++; } } else if (*src == '+') { *p++ = ' '; src++; } else { *p++ = *src++; } } *p = '\0'; } /**********************************************************************/ /* 获取MIME类型 */ /**********************************************************************/ const char *get_mime_type(const char *filename) { const char *dot = strrchr(filename, '.'); if (!dot) return "text/plain"; if (strcasecmp(dot, ".html") == 0 || strcasecmp(dot, ".htm") == 0) return "text/html"; if (strcasecmp(dot, ".css") == 0) return "text/css"; if (strcasecmp(dot, ".js") == 0) return "application/javascript"; if (strcasecmp(dot, ".jpg") == 0 || strcasecmp(dot, ".jpeg") == 0) return "image/jpeg"; if (strcasecmp(dot, ".png") == 0) return "image/png"; if (strcasecmp(dot, ".gif") == 0) return "image/gif"; if (strcasecmp(dot, ".json") == 0) return "application/json"; if (strcasecmp(dot, ".ico") == 0) return "image/x-icon"; return "text/plain"; } /**********************************************************************/ /* 记录请求日志 */ /**********************************************************************/ void log_request(const char *method, const char *url, int client) { time_t now = time(NULL); struct tm *tm = localtime(&now); char timestamp[64]; strftime(timestamp, sizeof(timestamp), "%Y-%m-%d %H:%M:%S", tm); struct sockaddr_in addr; socklen_t addr_len = sizeof(addr); getpeername(client, (struct sockaddr*)&addr, &addr_len); char *ip = inet_ntoa(addr.sin_addr); printf("[%s] %s %s %s\n", timestamp, ip, method, url); } /**********************************************************************/ /* 处理目录列表 */ /**********************************************************************/ void serve_directory(int client, const char *path) { char buf[4096]; // 发送HTTP头 sprintf(buf, "HTTP/1.0 200 OK\r\n"); send(client, buf, strlen(buf), 0); sprintf(buf, SERVER_STRING); send(client, buf, strlen(buf), 0); sprintf(buf, "Content-Type: text/html\r\n"); send(client, buf, strlen(buf), 0); sprintf(buf, "\r\n"); send(client, buf, strlen(buf), 0); // 发送HTML头部 sprintf(buf, "<html><head><title>Index of %s</title></head>", path); send(client, buf, strlen(buf), 0); sprintf(buf, "<body><h1>Index of %s</h1><ul>", path); send(client, buf, strlen(buf), 0); // 打开目录 DIR *dir = opendir(path); if (dir) { struct dirent *ent; while ((ent = readdir(dir)) != NULL) { // 跳过隐藏文件 if (ent->d_name[0] == '.') continue; char full_path[1024]; sprintf(full_path, "%s/%s", path, ent->d_name); struct stat st; stat(full_path, &st); char size_buf[32]; if (S_ISDIR(st.st_mode)) { strcpy(size_buf, "[DIR]"); } else { if (st.st_size < 1024) { sprintf(size_buf, "%ld B", st.st_size); } else if (st.st_size < 1024 * 1024) { sprintf(size_buf, "%.1f KB", st.st_size / 1024.0); } else { sprintf(size_buf, "%.1f MB", st.st_size / (1024.0 * 1024)); } } sprintf(buf, "<li><a href=\"%s\">%s</a> - %s</li>", ent->d_name, ent->d_name, size_buf); send(client, buf, strlen(buf), 0); } closedir(dir); } // 发送HTML尾部 sprintf(buf, "</ul></body></html>\r\n"); send(client, buf, strlen(buf), 0); } /**********************************************************************/ /* 400 Bad Request */ /**********************************************************************/ void bad_request(int client) { char buf[1024]; sprintf(buf, "HTTP/1.0 400 BAD REQUEST\r\n"); send(client, buf, strlen(buf), 0); sprintf(buf, "Content-type: text/html\r\n"); send(client, buf, strlen(buf), 0); sprintf(buf, "\r\n"); send(client, buf, strlen(buf), 0); sprintf(buf, "<html><body><h1>400 Bad Request</h1></body></html>\r\n"); send(client, buf, strlen(buf), 0); } /**********************************************************************/ /* 403 Forbidden */ /**********************************************************************/ void forbidden(int client) { char buf[1024]; sprintf(buf, "HTTP/1.0 403 Forbidden\r\n"); send(client, buf, strlen(buf), 0); sprintf(buf, SERVER_STRING); send(client, buf, strlen(buf), 0); sprintf(buf, "Content-Type: text/html\r\n"); send(client, buf, strlen(buf), 0); sprintf(buf, "\r\n"); send(client, buf, strlen(buf), 0); sprintf(buf, "<html><body><h1>403 Forbidden</h1><p>Access to this resource is denied.</p></body></html>\r\n"); send(client, buf, strlen(buf), 0); } /**********************************************************************/ /* 发送文件内容 */ /**********************************************************************/ void cat(int client, FILE *resource) { char buf[65536]; fgets(buf, sizeof(buf), resource); while (!feof(resource)) { send(client, buf, strlen(buf), 0); fgets(buf, sizeof(buf), resource); } } /**********************************************************************/ /* 500 Internal Server Error */ /**********************************************************************/ void cannot_execute(int client) { char buf[1024]; sprintf(buf, "HTTP/1.0 500 Internal Server Error\r\n"); send(client, buf, strlen(buf), 0); sprintf(buf, "Content-type: text/html\r\n"); send(client, buf, strlen(buf), 0); sprintf(buf, "\r\n"); send(client, buf, strlen(buf), 0); sprintf(buf, "<html><body><h1>500 Internal Server Error</h1><p>CGI execution failed.</p></body></html>\r\n"); send(client, buf, strlen(buf), 0); } /**********************************************************************/ /* 错误处理 */ /**********************************************************************/ void error_die(const char *sc) { perror(sc); exit(1); } /**********************************************************************/ /* 读取一行 */ /**********************************************************************/ int get_line(int sock, char *buf, int size) { int i = 0; char c = '\0'; int n; while ((i < size - 1) && (c != '\n')) { n = recv(sock, &c, 1, 0); if (n > 0) { if (c == '\r') { n = recv(sock, &c, 1, MSG_PEEK); if ((n > 0) && (c == '\n')) recv(sock, &c, 1, 0); else c = '\n'; } buf[i] = c; i++; } else c = '\n'; } buf[i] = '\0'; return(i); } /**********************************************************************/ /* 发送HTTP头 */ /**********************************************************************/ void headers(int client, const char *filename, const char *content_type) { char buf[1024]; (void)filename; // 未使用 strcpy(buf, "HTTP/1.0 200 OK\r\n"); send(client, buf, strlen(buf), 0); strcpy(buf, SERVER_STRING); send(client, buf, strlen(buf), 0); sprintf(buf, "Content-Type: %s\r\n", content_type); send(client, buf, strlen(buf), 0); strcpy(buf, "\r\n"); send(client, buf, strlen(buf), 0); } /**********************************************************************/ /* 404 Not Found */ /**********************************************************************/ void not_found(int client) { char buf[1024]; sprintf(buf, "HTTP/1.0 404 NOT FOUND\r\n"); send(client, buf, strlen(buf), 0); sprintf(buf, SERVER_STRING); send(client, buf, strlen(buf), 0); sprintf(buf, "Content-Type: text/html\r\n"); send(client, buf, strlen(buf), 0); sprintf(buf, "\r\n"); send(client, buf, strlen(buf), 0); sprintf(buf, "<html><body><h1>404 Not Found</h1><p>The requested URL was not found on this server.</p></body></html>\r\n"); send(client, buf, strlen(buf), 0); } /**********************************************************************/ /* 服务静态文件(修复二进制文件处理) */ /**********************************************************************/ void serve_file(int client, const char *filename) { FILE *resource = NULL; int numchars = 1; char buf[1024]; size_t bytes_read; long file_size; // 丢弃请求头 buf[0] = 'A'; buf[1] = '\0'; while ((numchars > 0) && strcmp("\n", buf)) numchars = get_line(client, buf, sizeof(buf)); // 使用二进制模式打开文件 resource = fopen(filename, "rb"); if (resource == NULL) { not_found(client); return; } // 获取文件大小 fseek(resource, 0, SEEK_END); file_size = ftell(resource); fseek(resource, 0, SEEK_SET); // 发送HTTP头 const char *content_type = get_mime_type(filename); // 创建并发送头部 char header_buf[2048]; sprintf(header_buf, "HTTP/1.0 200 OK\r\n"); send(client, header_buf, strlen(header_buf), 0); sprintf(header_buf, SERVER_STRING); send(client, header_buf, strlen(header_buf), 0); sprintf(header_buf, "Content-Type: %s\r\n", content_type); send(client, header_buf, strlen(header_buf), 0); sprintf(header_buf, "Content-Length: %ld\r\n", file_size); send(client, header_buf, strlen(header_buf), 0); sprintf(header_buf, "\r\n"); send(client, header_buf, strlen(header_buf), 0); // 使用二进制模式发送文件内容 while ((bytes_read = fread(buf, 1, sizeof(buf), resource)) > 0) { ssize_t sent = send(client, buf, bytes_read, MSG_NOSIGNAL); if (sent < 0) { // 处理发送错误(如连接关闭) break; } } fclose(resource); } /**********************************************************************/ /* 启动服务器 */ /**********************************************************************/ int startup(unsigned short *port) { int httpd = 0; struct sockaddr_in name; /* 创建socket */ httpd = socket(PF_INET, SOCK_STREAM, 0); if (httpd == -1) error_die("socket"); memset(&name, 0, sizeof(name)); name.sin_family = AF_INET; name.sin_port = htons(*port); name.sin_addr.s_addr = htonl(INADDR_ANY); /* 绑定地址 */ if (bind(httpd, (struct sockaddr *)&name, sizeof(name)) < 0) error_die("bind"); /* 若预设端口为0,随机取用可用端口*/ if (*port == 0) { socklen_t namelen = sizeof(name); if (getsockname(httpd, (struct sockaddr *)&name, &namelen) == -1) error_die("getsockname"); *port = ntohs(name.sin_port); } /* 监听连接 */ if (listen(httpd, 5) < 0) error_die("listen"); return(httpd); } /**********************************************************************/ /* 501 Not Implemented */ /**********************************************************************/ void unimplemented(int client) { char buf[1024]; sprintf(buf, "HTTP/1.0 501 Method Not Implemented\r\n"); send(client, buf, strlen(buf), 0); sprintf(buf, SERVER_STRING); send(client, buf, strlen(buf), 0); sprintf(buf, "Content-Type: text/html\r\n"); send(client, buf, strlen(buf), 0); sprintf(buf, "\r\n"); send(client, buf, strlen(buf), 0); sprintf(buf, "<html><body><h1>501 Not Implemented</h1><p>The requested method is not implemented.</p></body></html>\r\n"); send(client, buf, strlen(buf), 0); } // 设置套接字发送超时(在主循环accept后调用) void set_socket_timeout(int sockfd, int timeout_sec) { struct timeval tv; tv.tv_sec = timeout_sec; // 超时秒数 tv.tv_usec = 0; if (setsockopt(sockfd, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv)) < 0) { perror("setsockopt SO_SNDTIMEO failed"); } } /**********************************************************************/ /* 主函数(多进程实现)*/ /**********************************************************************/ int main(void) { int server_sock = -1; unsigned short port = 8080; int client_sock = -1; struct sockaddr_in client_name; socklen_t client_name_len = sizeof(client_name); pid_t pid; // 设置SIGCHLD处理函数避免僵尸进程 struct sigaction sa; sa.sa_handler = SIG_IGN; // 忽略SIGCHLD信号,自动回收子进程 sigemptyset(&sa.sa_mask); sa.sa_flags = SA_RESTART; if (sigaction(SIGCHLD, &sa, NULL) == -1) { perror("sigaction"); exit(EXIT_FAILURE); } server_sock = startup(&port); printf("HTTP server running on port %d\n", port); signal(SIGPIPE, SIG_IGN); // 忽略SIGPIPE信号 while (1) { /* 接受连接 */ client_sock = accept(server_sock, (struct sockaddr *)&client_name, &client_name_len); if (client_sock == -1) { perror("accept"); continue; } /* 创建子进程处理请求 */ pid = fork(); if (pid < 0) { perror("fork"); close(client_sock); } else if (pid == 0) { // 子进程 close(server_sock); // 关闭监听套接字(子进程不需要) // 动态分配内存传递socket描述符 int *pclient = malloc(sizeof(int)); if (!pclient) { perror("malloc failed"); close(client_sock); exit(EXIT_FAILURE); } *pclient = client_sock; accept_request(pclient); // 处理请求 exit(EXIT_SUCCESS); // 子进程退出 } else { // 父进程 close(client_sock); // 关闭客户端套接字(父进程不需要) } } close(server_sock); return 0; } 用windows浏览器向该webserver发送POST请求时报错net::ERR_CONNECTION_RESET,而Linux浏览器正常,试分析原因
08-09
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值