基于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解析模块. ...
随机推荐
- ASP.net core 2.0.0 中 asp.net identity 2.0.0 的基本使用(一)—修改数据库连接
开发环境:vs2017 版本:15.3.5 项目环境:.net framework 4.6.1 模板asp.net core 2.0 Web应用程序(模型视图控制器) 身份验证:个人用户账号 ...
- System包含的信息
System类中的属性值 System.getProperty()方法大全 System.out.println("java版本号:" + System.getProperty(& ...
- 解决页面引用百度地图API设置点的logo不显示问题
在写css时需要引用一个百度的api地图,却发现设置点的logo图片不能显示,后查阅百度测试发现是图片路径的问题: 在引用的下载的html页面找到 var icon = new BMap.Icon 将 ...
- linux_nginx环境配置
rpm -ivh https://mirrors.aliyun.com/epel/epel-release-latest-6.noarch.rpm # 安装阿里的epel源 国内使用web站点最多的w ...
- Storm保证消息处理
Guaranteeing Message Processing Storm保证每一个tuple被完全处理.Strom中一个核心的机制是它提供了一种跟踪tuple血统的能力,它使用了一种十分有效的方式跟 ...
- 输入和输出--IO流
JavaIO流 首先要理解这个"流"(stream)字:Java把不同的输入,输出源抽象成为流,通过流的方式允许Java程序使用相同的方式来访问不同的输入,输出源.把这里的&quo ...
- Jmeter_接口自动化基础流程概述
这里补一篇基础的操作吧,不然总觉得没底! 1:创建一个线程组 2:添加一个cookie管理器 33333 3:设置你的信息头管理器:application/json;text/plain;ch ...
- 怎样共享windows和linux之间的文件
注:本文参考自:https://www.howtogeek.com/176471/how-to-share-files-between-windows-and-linux/,相当于是原文的翻译. 一. ...
- 企业级Docker私有仓库部署(https)
部署环境 Centos7.3 x64 docker-ce-17.06.0 docker-compose-1.15.0 Python-2.7.5(系统默认) 部署目标 使用HTTPS协议 支持Clair ...
- Python之Suds库调用WCF实现复杂参数序列化
今年主要做自动化测技术支持工作,最近一直在做接口自动化这块,前些天在研究将web页面模拟http进行接口自动化,这周杭州那边想测试WCF服务,所以这两天一直在探索.遇到的第一个问题就是服务参数传参序列 ...