#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <pthread.h>
#define PORT 8080
#define BUFFER_SIZE 1024
void handle_client(int client_socket);
void handle_request(char *request, int client_socket);
char *get_header_value(char *header, char *key);
int main() {
// 创建服务器套接字
int server_socket = socket(AF_INET, SOCK_STREAM, 0);
if (server_socket == -1) {
perror("Create socket failed");
return -1;
}
// 设置服务器地址
struct sockaddr_in server_address{};
memset(&server_address, 0, sizeof(server_address));
server_address.sin_family = AF_INET;
server_address.sin_port = htons(PORT);
server_address.sin_addr.s_addr = htonl(INADDR_ANY);
// 绑定套接字到本地地址
if (bind(server_socket, (struct sockaddr *) &server_address, sizeof(server_address)) == -1) {
perror("Bind failed");
return -1;
}
// 监听端口
if (listen(server_socket, SOMAXCONN) == -1) {
perror("Listen failed");
return -1;
}
printf("Server started. Listening on port %d...\n", PORT);
while (1) {
// 接收连接请求
struct sockaddr_in client_address{};
socklen_t client_address_len = sizeof(client_address);
int client_socket = accept(server_socket, (struct sockaddr *) &client_address, &client_address_len);
if (client_socket == -1) {
perror("Accept failed");
continue;
}
printf("Client connected. IP address: %s\n", inet_ntoa(client_address.sin_addr));
// 处理客户端连接
pthread_t client_thread;
pthread_create(&client_thread, NULL, (void *(*)(void *)) handle_client, (void *) &client_socket);
pthread_detach(client_thread);
}
// 关闭服务器套接字
close(server_socket);
return 0;
}
void handle_client(int client_socket) {
char buffer[BUFFER_SIZE];
// 读取客户端发送的HTTP请求
ssize_t request_size = recv(client_socket, buffer, BUFFER_SIZE, 0);
if (request_size == -1) {
perror("Receive failed");
close(client_socket);
return;
}
buffer[request_size] = '\0';
// 处理HTTP请求
handle_request(buffer, client_socket);
// 关闭客户端套接字
close(client_socket);
}
void handle_request(char *request, int client_socket) {
char method[BUFFER_SIZE], uri[BUFFER_SIZE], http_version[BUFFER_SIZE];
char *header, *body;
// 解析HTTP请求
sscanf(request, "%s %s %s", method, uri, http_version);
// 处理GET请求
if (strcmp(method, "GET") == 0) {
// 构造响应消息
char *response = "HTTP/1.1 200 OK\r\n"
"Content-Type: text/html\r\n"
"\r\n"
"<html><body><h1>Hello, World!</h1></body></html>";
// 发送响应
send(client_socket, response, strlen(response), 0);
}
// 处理POST请求
else if (strcmp(method, "POST") == 0) {
// 查找Content-Length头部
header = strstr(request, "Content-Length");
if (header == NULL) {
// 没有Content-Length头部,不处理POST请求体
return;
}
// 解析Content-Length头部的值
int content_length = atoi(get_header_value(header, "Content-Length"));
// 查找请求体
body = strstr(request, "\r\n\r\n") + 4;
if (body == NULL) {
// 没有请求体
return;
}
// 处理POST请求体
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"
"Hello, World!";
// 发送响应
send(client_socket, response, strlen(response), 0);
} else {
// 不支持的HTTP方法,返回405 Method Not Allowed
char *response = "HTTP/1.1 405 Method Not Allowed\r\n"
"Content-Length: 0\r\n"
"\r\n";
send(client_socket, response, strlen(response), 0);
}
}
char *get_header_value(char *header, char *key) {
// 查找key
char *key_pos = strstr(header, key);
if (key_pos == NULL) { return NULL; }
// 查找value
char *value_pos = strchr(key_pos, ':');
if (value_pos == NULL) {
return NULL;
}
value_pos++;
// 跳过前面的空格
while (*value_pos == ' ') {
value_pos++;
}
// 查找结尾的\r\n
char *end_pos = strstr(value_pos, "\r\n");
if (end_pos == NULL) {
return NULL;
}
// 截取value
*end_pos = '\0';
return value_pos;
}
这是一个简单的单线程HTTP服务器,每次只能处理一个客户端连接。当客户端连接时,该程序会创建一个线程来处理该客户端连接,以允许多个客户端同时连接。对于HTTP请求,该程序会解析HTTP头部并根据不同的HTTP方法做出不同的响应。对于GET请求,该程序会返回一个HTML页面,对于POST请求,该程序会处理请求体并返回一个简单的文本响应。需要注意的是,此处的代码并没有做任何错误处理,实际应用中需要进行更完善的错误处理。