实战案例3:C语言实现的HTTP服务器

简介: 实战案例3:C语言实现的HTTP服务器

实战案例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));

 

// 处理

 

目录
相关文章
|
4天前
|
SQL 数据挖掘 数据库
服务器数据恢复—意外断电导致XenServer虚拟机不可用的数据恢复案例
服务器数据恢复环境: 一台服务器中有一组由4块STAT硬盘通过RAID卡组建的RAID10阵列,上层是XenServer虚拟化平台,虚拟机安装Windows Server操作系统,作为Web服务器使用。 服务器故障: 因机房异常断电导致服务器中一台VPS(Xen Server虚拟机)不可用,虚拟磁盘文件丢失。
服务器数据恢复—意外断电导致XenServer虚拟机不可用的数据恢复案例
|
12天前
|
网络协议
keepalived对后端服务器的监测方式实战案例
关于使用keepalived进行后端服务器TCP监测的实战案例,包括配置文件的编辑和keepalived服务的重启,以确保配置生效。
26 1
keepalived对后端服务器的监测方式实战案例
|
3天前
|
存储 人工智能 C语言
数据结构基础详解(C语言): 栈的括号匹配(实战)与栈的表达式求值&&特殊矩阵的压缩存储
本文首先介绍了栈的应用之一——括号匹配,利用栈的特性实现左右括号的匹配检测。接着详细描述了南京理工大学的一道编程题,要求判断输入字符串中的括号是否正确匹配,并给出了完整的代码示例。此外,还探讨了栈在表达式求值中的应用,包括中缀、后缀和前缀表达式的转换与计算方法。最后,文章介绍了矩阵的压缩存储技术,涵盖对称矩阵、三角矩阵及稀疏矩阵的不同压缩存储策略,提高存储效率。
|
2天前
|
存储 数据挖掘 Linux
服务器数据恢复—Linux操作系统网站服务器数据恢复案例
服务器数据恢复环境: 一台linux操作系统服务器上跑了几十个网站,服务器上只有一块SATA硬盘。 服务器故障: 服务器突然宕机,尝试再次启动失败。将硬盘拆下检测,发现存在坏扇区
|
3天前
|
开发者
HTTP状态码是由网页服务器返回的三位数字响应代码,用于表示请求的处理结果和状态
HTTP状态码是由网页服务器返回的三位数字响应代码,用于表示请求的处理结果和状态
9 1
|
5天前
|
存储 算法 C语言
C语言手撕实战代码_二叉排序树(二叉搜索树)_构建_删除_插入操作详解
这份二叉排序树习题集涵盖了二叉搜索树(BST)的基本操作,包括构建、查找、删除等核心功能。通过多个具体示例,如构建BST、查找节点所在层数、删除特定节点及查找小于某个关键字的所有节点等,帮助读者深入理解二叉排序树的工作原理与应用技巧。此外,还介绍了如何将一棵二叉树分解为两棵满足特定条件的BST,以及删除所有关键字小于指定值的节点等高级操作。每个题目均配有详细解释与代码实现,便于学习与实践。
|
5天前
|
存储 算法 C语言
C语言手撕实战代码_二叉树_构造二叉树_层序遍历二叉树_二叉树深度的超详细代码实现
这段代码和文本介绍了一系列二叉树相关的问题及其解决方案。其中包括根据前序和中序序列构建二叉树、通过层次遍历序列和中序序列创建二叉树、计算二叉树节点数量、叶子节点数量、度为1的节点数量、二叉树高度、特定节点子树深度、判断两棵树是否相似、将叶子节点链接成双向链表、计算算术表达式的值、判断是否为完全二叉树以及求二叉树的最大宽度等。每道题目均提供了详细的算法思路及相应的C/C++代码实现,帮助读者理解和掌握二叉树的基本操作与应用。
|
5天前
|
存储 算法 C语言
C语言手撕实战代码_循环单链表和循环双链表
本文档详细介绍了用C语言实现循环单链表和循环双链表的相关算法。包括循环单链表的建立、逆转、左移、拆分及合并等操作;以及双链表的建立、遍历、排序和循环双链表的重组。通过具体示例和代码片段,展示了每种算法的实现思路与步骤,帮助读者深入理解并掌握这些数据结构的基本操作方法。
|
5天前
|
算法 C语言 开发者
C语言手撕实战代码_单链表
本文档详细介绍了使用C语言实现单链表的各种基本操作和经典算法。内容涵盖单链表的构建、插入、查找、合并及特殊操作,如头插法和尾插法构建单链表、插入元素、查找倒数第m个节点、合并两个有序链表等。每部分均配有详细的代码示例和注释,帮助读者更好地理解和掌握单链表的编程技巧。此外,还提供了判断子链、查找公共后缀等进阶题目,适合初学者和有一定基础的开发者学习参考。
|
12天前
|
存储 运维 小程序
服务器数据恢复—双循环RAID5阵列数据恢复案例
服务器存储数据恢复环境: 一台存储中有一组由7块硬盘组建的RAID5阵列,存储中还有另外3块盘是raid中掉线的硬盘(硬盘掉线了,管理员只是添加一块的新的硬盘做rebuild,并没有将掉线的硬盘拔掉)。整个RAID5阵列的存储空间划分了一个LUN。 服务器存储故障: 硬盘出现故障导致存储中阵列瘫痪。 和管理员沟通,据管理员说是磁盘阵列中某些硬盘出现故障导致存储不可用,初步判断RAID中有硬盘掉线了。