``
c,#include,#include,#include,#include,#include,,int main(int argc, char *argv[]) {, int socket_desc, client_sock, c, read_size;, struct sockaddr_in server, client;, char client_message[2000];,, // 创建套接字, socket_desc = socket(AF_INET, SOCK_STREAM, 0);, if (socket_desc == -1) {, printf("无法创建套接字");, return 1;, }, puts("套接字创建成功");,, // 准备 sockaddr_in 结构体, server.sin_family = AF_INET;, server.sin_addr.s_addr = INADDR_ANY;, server.sin_port = htons(8888);,, // 绑定, if (bind(socket_desc, (struct sockaddr *)&server, sizeof(server))< 0) {, perror("绑定失败。错误");, return 1;, }, puts("绑定完成");,, // 监听, listen(socket_desc, 3);,, // 接受并处理连接, puts("等待连接...");, c = sizeof(struct sockaddr_in);, while ((client_sock = accept(socket_desc, (struct sockaddr *)&client, (socklen_t*)&c))) {, puts("连接已建立");,, // 接收消息, while ((read_size = recv(client_sock, client_message, 2000, 0)) > 0) {, // 发送消息回客户端, write(client_sock, client_message, strlen(client_message));, },, if (read_size == 0) {, puts("客户端断开连接");, fflush(stdout);, } else if (read_size == -1) {, perror("接收失败");, }, },, if (client_sock< 0) {, perror("接受失败");, return 1;, },, return 0;,},
``编写一个简单的Web服务器是一个有趣的项目,它可以帮助你理解网络编程的基本概念,以下是一个用C语言编写的简单Web服务器示例,这个服务器能够处理HTTP请求并返回简单的响应。
引入必要的头文件
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h>
定义端口和缓冲区大小
#define PORT 8080 #define BUFFER_SIZE 1024
主函数
int main() { int server_fd, new_socket; struct sockaddr_in address; int opt = 1; int addrlen = sizeof(address); char buffer[BUFFER_SIZE] = {0}; const char *hello = "HTTP/1.1 200 OK Content-Type: text/plain Content-Length: 12 Hello world!"; // 创建套接字文件描述符 if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) { perror("socket failed"); exit(EXIT_FAILURE); } // 绑定套接字到端口8080 if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &opt, sizeof(opt))) { perror("setsockopt"); exit(EXIT_FAILURE); } address.sin_family = AF_INET; address.sin_addr.s_addr = INADDR_ANY; address.sin_port = htons(PORT); if (bind(server_fd, (struct sockaddr *)&address, sizeof(address))<0) { perror("bind failed"); exit(EXIT_FAILURE); } if (listen(server_fd, 3) < 0) { perror("listen"); exit(EXIT_FAILURE); } if ((new_socket = accept(server_fd, (struct sockaddr *)&address, (socklen_t*)&addrlen))<0) { perror("accept"); exit(EXIT_FAILURE); } // 读取客户端发送的数据 read(new_socket, buffer, BUFFER_SIZE); printf("Request received: %s ", buffer); // 发送响应给客户端 send(new_socket, hello, strlen(hello), 0); printf("Hello message sent "); // 关闭套接字 close(new_socket); close(server_fd); return 0; }
编译和运行
将上述代码保存为simple_web_server.c
,然后使用以下命令进行编译和运行:
gcc -o simple_web_server simple_web_server.c ./simple_web_server
测试服务器
打开浏览器,访问http://localhost:8080
,你应该会看到"Hello world!"的消息。
相关问题与解答
问题1:如何修改服务器以处理多个并发连接?
解答:要处理多个并发连接,可以使用多线程或多进程,以下是使用多线程的示例:
#include <pthread.h> void *handle_client(void *socket_desc) { int sock = *(int*)socket_desc; char buffer[BUFFER_SIZE] = {0}; const char *hello = "HTTP/1.1 200 OK Content-Type: text/plain Content-Length: 12 Hello world!"; // 读取客户端发送的数据 read(sock, buffer, BUFFER_SIZE); printf("Request received: %s ", buffer); // 发送响应给客户端 send(sock, hello, strlen(hello), 0); printf("Hello message sent "); // 关闭套接字 close(sock); free(socket_desc); return NULL; } int main() { int server_fd, new_socket; struct sockaddr_in address; int opt = 1; int addrlen = sizeof(address); pthread_t thread_id; // 创建套接字文件描述符 if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) { perror("socket failed"); exit(EXIT_FAILURE); } // 绑定套接字到端口8080 if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &opt, sizeof(opt))) { perror("setsockopt"); exit(EXIT_FAILURE); } address.sin_family = AF_INET; address.sin_addr.s_addr = INADDR_ANY; address.sin_port = htons(PORT); if (bind(server_fd, (struct sockaddr *)&address, sizeof(address))<0) { perror("bind failed"); exit(EXIT_FAILURE); } if (listen(server_fd, 3) < 0) { perror("listen"); exit(EXIT_FAILURE); } while((new_socket = accept(server_fd, (struct sockaddr *)&address, (socklen_t*)&addrlen))) { printf("Connection established "); int *new_sock = malloc(sizeof(int)); *new_sock = new_socket; if(pthread_create(&thread_id, NULL, handle_client, (void*) new_sock) < 0) { perror("could not create thread"); return 1; } printf("Handler assigned "); } if (new_socket < 0) { perror("accept failed"); exit(EXIT_FAILURE); } return 0; }
问题2:如何让服务器支持静态文件服务?
解答:要让服务器支持静态文件服务,你需要解析HTTP请求中的文件路径,并根据路径读取相应的文件内容返回给客户端,以下是一个简单的示例:
#include <fcntl.h> #include <sys/stat.h> #include <dirent.h> #include <stdbool.h> #include <errno.h> const char *get_mime_type(const char *filename) { if (strstr(filename, ".html")) return "text/html"; if (strstr(filename, ".jpg") || strstr(filename, ".jpeg")) return "image/jpeg"; if (strstr(filename, ".png")) return "image/png"; if (strstr(filename, ".css")) return "text/css"; if (strstr(filename, ".js")) return "application/javascript"; return "application/octet-stream"; // default mime type } void handle_client(int client_socket) { char buffer[BUFFER_SIZE] = {0}; read(client_socket, buffer, BUFFER_SIZE); printf("Request received: %s ", buffer); char method[10], path[100], protocol[10]; sscanf(buffer, "%s %s %s", method, path, protocol); printf("Method: %s, Path: %s, Protocol: %s ", method, path, protocol); if (strcmp(method, "GET") != 0) { char *response = "HTTP/1.1 405 Method Not Allowed\r \r "; send(client_socket, response, strlen(response), 0); close(client_socket); return; } if (path[0] != '/') { // relative path to absolute path conversion char abs_path[128]; sprintf(abs_path, ".%s", path); // assuming the current directory is the root directory for simplicity strcpy(path, abs_path); } FILE *file = fopen(path + 1, "rb"); // skip the first character which is '/' in path if (!file) { char *response = "HTTP/1.1 404 Not Found\r \r "; send(client_socket, response, strlen(response), 0); close(client_socket); return; } fseek(file, 0, SEEK_END); long file_size = ftell(file); rewind(file); char *content_type = get_mime_type(path + 1); // skip the first character which is '/' in path for mime type detection as well char *header = "HTTP/1.1 200 OK\r "; char content_length[50]; sprintf(content_length, "Content-Length: %ld\r ", file_size); char *response = malloc(file_size + strlen(header) + strlen(content_length) + strlen("\r \r ") + 1); strcpy(response, header); strcat(response, "Content-Type: "); strcat(response, content_type); strcat(response, "\r "); strcat(response, content_length); strcat(response, "\r \r "); send(client_socket, response, strlen(response), 0); // send header first free(response); // free header memory after sending it out char data[BUFFER_SIZE]; // buffer to store file chunks to send them one by one to avoid large memory allocation at once for big files. while (!feof(file)) { // reading and sending file in chunks of this way can be useful when dealing with larger files to avoid high memory usage. int bytesRead = fread(data, 1, BUFFER_SIZE, file); // read a chunk of data from the file into 'data' buffer. send(client_socket, data, bytesRead, 0); // send the chunk of data to the client. } // end of while loop. The loop will continue until the entire file has been read and sent to the client. It ensures that even large files are handled efficiently without consuming too much memory at once. This approach is beneficial for handling large files or when dealing with limited system resources. By reading and sending the file in manageable chunks, it helps prevent high memory usage issues and ensures smoother operation even under constrained conditions.
到此,以上就是小编对于“c编写一个简单web服务器”的问题就介绍到这了,希望介绍的几点解答对大家有用,有任何问题和不懂的,欢迎各位朋友在评论区讨论,给我留言。