实战案例3:C语言实现的HTTP服务器
详细解析如何用C语言实现一个基本的HTTP服务器,处理GET和POST请求。
创建一个简单的HTTP服务器以处理GET和POST请求在C语言中是一个很好的学习项目,因为它涉及到了网络编程、字符串处理以及HTTP协议的基础知识。下面,我将逐步介绍如何使用C语言和socket编程来实现这样的服务器。
1. 准备工作
首先,确保你的系统上安装了C编译器,如GCC。此外,你需要了解socket编程的基本概念,包括TCP/IP协议栈、套接字(sockets)等。
2. 编写HTTP服务器的基本框架
2.1 包含必要的头文件
#include <stdio.h> |
#include <stdlib.h> |
#include <string.h> |
#include <unistd.h> |
#include <netinet/in.h> |
#include <sys/socket.h> |
2.2 初始化socket
int create_socket(int port) { |
int server_fd, yes = 1; |
struct sockaddr_in address; |
int opt = 1; |
|
if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) { |
perror("socket failed"); |
exit(EXIT_FAILURE); |
} |
|
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); |
} |
|
return server_fd; |
} |
2.3 处理HTTP请求
你需要解析传入的HTTP请求,并根据请求类型(GET或POST)来响应。这里为了简化,我们仅处理GET请求,并发送一个简单的HTML页面作为响应。
void handle_request(int sock) { |
char buffer[1024] = {0}; |
read(sock, buffer, 1024); |
|
printf("HTTP request:\n%s\n", buffer); |
|
// 这里假设只处理GET请求 |
if (strstr(buffer, "GET / ") != NULL) { |
const char *http_response = "HTTP/1.1 200 OK\nContent-Type: text/html\n\n<html><body><h1>Hello, World!</h1></body></html>"; |
write(sock, http_response, strlen(http_response)); |
} |
|
close(sock); |
} |
2.4 主函数
int main(int argc, char *argv[]) { |
int server_fd, new_socket; |
struct sockaddr_in address; |
int opt = sizeof(address); |
|
if (argc != 2) { |
fprintf(stderr, "Usage: %s <port>\n", argv[0]); |
exit(EXIT_FAILURE); |
} |
|
server_fd = create_socket(atoi(argv[1])); |
|
while (1) { |
if ((new_socket = accept(server_fd, (struct sockaddr *)&address, (socklen_t*)&opt)) < 0) { |
perror("accept"); |
exit(EXIT_FAILURE); |
} |
|
// 创建子进程处理请求 |
pid_t pid = fork(); |
|
if (pid == 0) { |
// 子进程 |
close(server_fd); |
handle_request(new_socket); |
exit(0); |
} else { |
// 父进程 |
close(new_socket); |
} |
} |
|
return 0; |
} |
3. 编译和运行
将上述代码保存为http_server.c,并使用GCC编译:
gcc http_server.c -o http_server |
然后,运行服务器:
./http_server 8080 |
在浏览器中访问http://localhost:8080/,你应该能看到“Hello, World!”的页面。
实战案例3:C语言实现的HTTP服务器(扩展)
在构建一个简单的HTTP服务器时,我们需要处理网络通信、请求解析以及响应生成等多个技术环节。以下是一个详细的步骤和代码示例,用于创建一个能够处理GET请求的HTTP服务器,并返回“Hello, World!”的HTML页面。此代码将基于C语言,使用标准的socket编程技术。
1. 包含必要的头文件
首先,我们需要包含处理网络通信和字符串操作所需的头文件。
#include <stdio.h> |
#include <stdlib.h> |
#include <string.h> |
#include <unistd.h> |
#include <sys/socket.h> |
#include <netinet/in.h> |
#include <arpa/inet.h> |
2. 定义常量和全局变量
为了方便管理,我们定义一些常量来表示网络地址族、套接字类型以及HTTP响应等。
#define PORT 8080 |
#define BUFFER_SIZE 1024 |
|
const char* http_response = |
"HTTP/1.1 200 OK\r\n" |
"Content-Type: text/html\r\n" |
"\r\n" |
"<html><body><h1>Hello, World!</h1></body></html>"; |
3. 创建套接字函数
接下来,我们编写一个函数来创建并配置套接字。
int create_socket(int port) { |
int server_fd, yes = 1; |
struct sockaddr_in address; |
int opt = 1; |
|
if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) { |
perror("socket failed"); |
exit(EXIT_FAILURE); |
} |
|
if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &opt, sizeof(opt)) < 0) { |
perror("setsockopt"); |
close(server_fd); |
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"); |
close(server_fd); |
exit(EXIT_FAILURE); |
} |
|
if (listen(server_fd, 3) < 0) { |
perror("listen"); |
close(server_fd); |
exit(EXIT_FAILURE); |
} |
|
return server_fd; |
} |
4. 处理HTTP请求的函数
然后,我们定义一个函数来接收HTTP请求,并发送响应。
void handle_request(int sock) { |
char buffer[BUFFER_SIZE] = {0}; |
int valread = read(sock, buffer, BUFFER_SIZE); |
printf("HTTP request:\n%s\n", buffer); |
|
if (strstr(buffer, "GET / ") != NULL) { |
write(sock, http_response, strlen(http_response)); |
} else { |
// 可以处理其他类型的HTTP请求或发送错误响应 |
const char* error_response = |
"HTTP/1.1 404 Not Found\r\n" |
"Content-Type: text/plain\r\n" |
"\r\n" |
"404 Not Found"; |
write(sock, error_response, strlen(error_response)); |
} |
|
close(sock); |
} |
5. 主函数
最后,我们在主函数中启动服务器,并等待连接。
int main(int argc, char *argv[]) { |
int server_fd = create_socket(PORT); |
struct sockaddr_in client_addr; |
socklen_t len = sizeof(client_addr); |
|
printf("Server is listening on port %d...\n", PORT); |
|
while (1) { |
int sock = accept(server_fd, (struct sockaddr *)&client_addr, &len); |
if (sock < 0) { |
perror("accept failed"); |
continue; |
} |
|
printf("Accepted new connection from %s:%d\n", |
inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port)); |
|
// 处理 |