基于epoll实现简单的web服务器
1. 简介
epoll 是 Linux 平台下特有的一种 I/O 复用模型实现,于 2002 年在 Linux kernel 2.5.44 中被引入。在 epoll 之前,Unix/Linux 平台下的 I/O 复用模型包含 select 和 poll 两个系统调用。随着因特网的发展,因特网的用户量越来越大,C10K 问题出现。基于 select 和 poll 编写的网络服务已经不能满足不能满足用户的需求了,业界迫切希望更高效的系统调用出现。在此背景下,FreeBSD 的 kqueue 和 Linux 的 epoll 被研发了出来。kqueue 和 epoll 的出现,终结了 C10K 问题,C10K 问题就此作古。
因为 Linux 系统的广泛应用,所以大家在说 I/O 复用时,更多的是想到了 epoll,而不是 kqueue,本文也不例外。本篇文章不会涉及 kqueue,大家有兴趣可以自己看看。
2. 基于 epoll 实现 web 服务器
在 Linux 中,epoll 并不是一个系统调用,而是 epoll_create、epoll_ctl 和 epoll_wait 三个系统调用的统称。关于这三个系统调用的细节,这里就不说明了,大家可以自己去查 man-page。接下来,我们来直接看一个例子,这个例子基于 epoll 和 TinyHttpd 实现了一个 I/O 复用版的 HTTP Server。在上代码前,我们先来演示这个玩具版 HTTP Server 的效果。

上面就是玩具版 HTTP Server 的运行效果了,看起来还行。在我第一次把它成功跑起来的时候,感觉很奇妙。好了,看完效果,接下来看代码吧,如下:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/sysinfo.h>
#include <sys/epoll.h>
#include <signal.h>
#include <fcntl.h>
#include <sys/wait.h>
#include <sys/types.h>
#include "httpd.h"
#define DEFAULT_PORT 8080
#define MAX_EVENT_NUM 1024
#define INFTIM -1
void process(int);
void handle_subprocess_exit(int);
int main(int argc, char *argv[])
{
struct sockaddr_in server_addr;
int listen_fd;
int cpu_core_num;
int on = 1;
listen_fd = socket(AF_INET, SOCK_STREAM, 0);
fcntl(listen_fd, F_SETFL, O_NONBLOCK); // 设置 listen_fd 为非阻塞
setsockopt(listen_fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
bzero(&server_addr, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
server_addr.sin_port = htons(DEFAULT_PORT);
if (bind(listen_fd, (struct sockaddr *)&server_addr, sizeof(server_addr)) == -1) {
perror("bind error, message: ");
exit(1);
}
if (listen(listen_fd, 5) == -1) {
perror("listen error, message: ");
exit(1);
}
printf("listening 8080\n");
signal(SIGCHLD, handle_subprocess_exit);
cpu_core_num = get_nprocs();
printf("cpu core num: %d\n", cpu_core_num);
// 根据 CPU 数量创建子进程,为了演示“惊群现象”,这里多创建一些子进程
for (int i = 0; i < cpu_core_num * 2; i++) {
pid_t pid = fork();
if (pid == 0) { // 子进程执行此条件分支
process(listen_fd);
exit(0);
}
}
while (1) {
sleep(1);
}
return 0;
}
void process(int listen_fd)
{
int conn_fd;
int ready_fd_num;
struct sockaddr_in client_addr;
int client_addr_size = sizeof(client_addr);
char buf[128];
struct epoll_event ev, events[MAX_EVENT_NUM];
// 创建 epoll 实例,并返回 epoll 文件描述符
int epoll_fd = epoll_create(MAX_EVENT_NUM);
ev.data.fd = listen_fd;
ev.events = EPOLLIN;
// 将 listen_fd 注册到刚刚创建的 epoll 中
if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, listen_fd, &ev) == -1) {
perror("epoll_ctl error, message: ");
exit(1);
}
while(1) {
// 等待事件发生
ready_fd_num = epoll_wait(epoll_fd, events, MAX_EVENT_NUM, INFTIM);
printf("[pid %d]
基于epoll实现简单的web服务器的更多相关文章
- 基于python2【重要】怎么自行搭建简单的web服务器
基本流程:1.需要的支持 1)python本身有SimpleHTTPServer 2)ForkStaticServer.py支持,该文件放在python7目录下 3)将希望共享 ...
- 自己动手模拟开发一个简单的Web服务器
开篇:每当我们将开发好的ASP.NET网站部署到IIS服务器中,在浏览器正常浏览页面时,可曾想过Web服务器是怎么工作的,其原理是什么?“纸上得来终觉浅,绝知此事要躬行”,于是我们自己模拟一个简单的W ...
- 一个简单的web服务器
写在前面 新的一年了,新的开始,打算重新看一遍asp.net本质论这本书,再重新认识一下,查漏补缺,认认真真的过一遍. 一个简单的web服务器 首先需要引入命名空间: System.Net,关于网络编 ...
- Tomcat剖析(一):一个简单的Web服务器
Tomcat剖析(一):一个简单的Web服务器 1. Tomcat剖析(一):一个简单的Web服务器 2. Tomcat剖析(二):一个简单的Servlet服务器 3. Tomcat剖析(三):连接器 ...
- 自己模拟的一个简单的web服务器
首先我为大家推荐一本书:How Tomcat Works.这本书讲的很详细的,虽然实际开发中我们并不会自己去写一个tomcat,但是对于了解Tomcat是如何工作的还是很有必要的. Servlet容器 ...
- 《深度解析Tomcat》 第一章 一个简单的Web服务器
本章介绍Java Web服务器是如何运行的.从中可以知道Tomcat是如何工作的. 基于Java的Web服务器会使用java.net.Socket类和java.net.ServerSocket类这两个 ...
- 基于Docker和Golang搭建Web服务器
1 场景描述 基于centos7的docker镜像搭建golang开发环境 在docker容器内,使用golang实现一个Web服务器 启动docker容器,并在容器内启动Web服务器 我购买了一个最 ...
- 如何用PHP/MySQL为 iOS App 写一个简单的web服务器(译) PART1
原文:http://www.raywenderlich.com/2941/how-to-write-a-simple-phpmysql-web-service-for-an-ios-app 作为一个i ...
- 使用 Nodejs 搭建简单的Web服务器
使用Nodejs搭建Web服务器是学习Node.js比较全面的入门教程,因为要完成一个简单的Web服务器,你需要学习Nodejs中几个比较重要的模块,比如:http协议模块.文件系统.url解析模块. ...
随机推荐
- 【故障】MySQL主从同步故障-Slave_SQL_Running: No
转自:http://www.linuxidc.com/Linux/2014-02/96945.htm 故障现象:进入slave服务器,运行:mysql> show slave status\G ...
- Java线程-异常处理
在Java多线程程序中,所有线程都不允许抛出未捕获的checked exception,也就是说各个线程需要自己把自己的checked exception处理掉.这一点是通过java.lang.Run ...
- CentOS7.x机器安装Azure CLI2.0
安装Azure CLI 2.0的前提是:机器中必须有 Python 2.7.x 或 Python 3.x.如果机器中没有其中任何一个Python的版本,请及时安装 1.准备一台CentOS 7.3的机 ...
- mysql5.7安装配置,常用命令,常见问题
1.安装配置 参考:http://www.cnblogs.com/Fiona20170420/p/6738185.html 1. 下载 2. 解压缩 3. 添加path环境变量,路径指向mysql所在 ...
- Linux使用top与free命令查看CPU与内存使用情况
top命令: 显示内容解释: 第一行top分别为:当前时间:系统运行天数:使用者个数:系统负载的平均值,后面的三个值分别为1分钟前.5分钟前.15分钟前进程的平均数,这个数值超过 CPU 数目时,说明 ...
- CentOS之7与6的区别
前言 centos7与6之间最大的差别就是初始化技术的不同,7采用的初始化技术是Systemd,并行的运行方式,除了这一点之外,服务启动.开机启动文件.网络命令方面等等,都说6有所不同.让我们先来了解 ...
- JDK及Tomcat集成到MyEclipse
JDK及Tomcat集成到MyEclipse 1.安装好MyEclipse 2.破解 3.配置环境JDK D:\jdk1.6.0_21\bin; ==>放在系统path前面 4.打开MyEcli ...
- img标签实现和背景图一样的显示效果——object-fit和object-positon
不知大家在做前端页面的时候,有没有遇到类似这样的问题:有一个不是正方形的图片,可能是宽度大于高度的,也可能是高度大于宽度的,而你又并不想用背景图的方式来做,要实现用img标签来让此图片显示出一个正方形 ...
- zookeeper 实现分布式锁zookeeper 使用 Curator 示例监听、分布式锁
下载地址: http://download.csdn.net/download/ttyyadd/10239642
- 以C语言为例的程序性能优化 --《深入理解计算机系统》第五章读书笔记
其实大多数的编译器本身就能提供一些简单的优化,比如gcc就能通过使用 -O2 或者 -O3 的选项来优化程序.但编译器的优化始终也是有限,因为它必须小心翼翼保证优化过程不对程序的功能有改动.故而程序员 ...