epoll编写web服务器

编写一个简单的web服务器,向每一个连接服务器的网页浏览器返回一行文本。

脚本核心在web服务器的初始化过程中调用select.epoll(),注册服务器的文件描述符,已达到事件通知的目的。

 1 #!/usr/bin/env python
 2 #-*- coding:utf-8 -*-
 3
 4 import socket
 5 import select
 6 import argparse
 7
 8 SERVER_HOST = ‘localhost‘
 9
10 EOL1 = b‘\n\n‘
11 EOL2 = b‘\n\r\n‘
12 SERVER_RESPONSE = b"""HTTP/1.1 200 OK\r\nDate:Mon, 1 Apr 2013 01:01:01 GMT\r\nContent-Type:text/plain\r\nContent-Length: 25\r\n\r\nHello from Epoll Server!"""
13
14 class EpollServer(object):
15     """ a socket server using epoll"""
16     def __init__(self, host=SERVER_HOST, port=0):
17         self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
18         #创建套接字
19         self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
20         #设置当前套接字选项为可重用
21         self.sock.bind((host, port))#绑定
22         self.sock.listen(1)#监听
23         self.sock.setblocking(0)#设置套接字模式为非阻塞
24         self.sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
25         #socket阻塞模式自动开启Nagle算法。设置套接字选项关闭。Nagle算法用于对缓冲区内的一定数量的消息进行自动连接。
26         print "Started Epoll Server"
27         self.epoll = select.epoll()#创建epoll对象
28         self.epoll.register(self.sock.fileno(), select.EPOLLIN)
29            #为该socket的read event注册interest
30            #EPOLLIN表示对应的文件描述符可以读,包括对端SOCKET正常关闭
31            #fileno()返回的是该socket的一个整型文件描述符
32
33     def run(self):
34         """Executes epoll server operation"""
35         try:
36             connections = {}    #连接对象与socket对象的映射
37             requests = {}
38             responses = {}
39             while True:
40                 events = self.epoll.poll(1)
41                 #查询epoll对象是否可能发生任何interest的事件。1等待一秒
42                 for fileno, event in events:#遍历事件
43                     #如果事件发生在服务器
44                     if fileno == self.sock.fileno():
45                         connection, address = self.sock.accept()#接收客户端socket和地址
46                         connection.setblocking(0)#设置非阻塞模式
47                         self.epoll.register(connection.fileno(), select.EPOLLIN)
48                         #为新的socket的read event注册兴趣
49                         connections[connection.fileno()] = connection#添加到connections
50                         requests[connection.fileno()] = b‘‘
51                         responses[connection.fileno()] = SERVER_RESPONSE#要发送的内容
52
53                     #如果一个读事件发生在客户端,那么读取从客户端发来的新数据
54                     elif event & select.EPOLLIN:
55                         requests[fileno] += connections[fileno].recv(1024)
56                         if EOL1 in requests[fileno] or EOL2 in requests[fileno]:
57                             self.epoll.modify(fileno, select.EPOLLOUT)
58                              #注销对read event的interest,注册对write event的interest
59                              print(‘-‘*40 + ‘\n‘ + requests[fileno].decode()[:-2])
60                             #输出完整的请求,去除最后一个\r\n
61
62                      #如果一个写事件发生在客户端,那么可能要接受来自客户端的新数据
63                     elif event & select.EPOLLOUT:
64                     #EPOLLOUT表示对应的文件描述符可以写
65                         byteswritten = connections[fileno].send(responses[fileno])
66                         responses[fileno] = responses[fileno][byteswritten:]
67                         if len(responses[fileno]) == 0:#如果无响应
68                             self.epoll.modify(fileno, 0)#禁用interest
69                             connections[fileno].shutdown(socket.SHUT_RDWR)
70                             #将对应的socket连接关闭
71
72                     #如果一个中止事件发生在客户端
73                     elif event & select.EPOLLHUP:
74                     #EPOLLHUP表示对应的文件描述符被挂断
75                         self.epoll.unregister(fileno)#注销客户端interest
76                         connections[fileno].close()#关闭socket连接
77                         del connections[fileno]#删除映射
78         finally:
79             self.epoll.unregister(self.sock.fileno())#注销服务器interest
80             self.epoll.close()#关闭服务器epoll
81             self.sock.close()#关闭服务器socket
82
83 if __name__ == ‘__main__‘:
84     parser = argparse.ArgumentParser(description=‘Socket Server Example with Epoll‘)
85     parser.add_argument(‘--port‘, action="store", dest="port", type=int, required=True)
86     given_args = parser.parse_args()
87     port = given_args.port
88     server = EpollServer(host=SERVER_HOST, port=port)
89     server.run()

参考文献: 《Python Network Programming Cookbook》

      http://scotdoyle.com/python-epoll-howto.html#source-code

时间: 2024-10-15 05:56:26

epoll编写web服务器的相关文章

《Python入门》第一个Python Web程序——简单的Web服务器

上一篇讲了<Python入门>Windows 7下Python Web开发环境搭建笔记,接下来讲一下Python语言Web服务的具体实现:第一个Python Web程序--简单的Web服务器. 与其它Web后端语言不同,Python语言需要自己编写Web服务器. 如果你使用一些现有的框架的话,可以省略这一步: 如果你使用Python CGI编程的话,也可以省略这一步: 用Python建立最简单的web服务器 利用Python自带的包可以建立简单的web服务器.在DOS里cd到准备做服务器根目录

《Go语言入门》第一个Go语言Web程序——简单的Web服务器

概述 上一篇讲了 <Go语言入门>第一个Go语言程序--HelloWorld,接下来讲一下Go语言Web开发入门必修课:第一个Go语言Web程序--简单的Web服务器. 与其它Web后端语言不同,Go语言需要自己编写Web服务器. 有关本地环境的搭建与基础学习,请参考: <Go语言入门>如何在Windows下安装Go语言编程环境 Go语言Web应用:IBM的云平台Bluemix使用初体验--创建Go语言 Web 应用程序,添加并使用语言翻译服务 Web服务器代码 Google在ht

Go Web服务器和图片

Web 服务器 包 http 通过任何实现了 http.Handler 的值来响应 HTTP 请求: package http type Handler interface { ServeHTTP(w ResponseWriter, r *Request) } 在这个例子中,类型 Hello 实现了 `http.Handler`. 访问 http://localhost:4000/ 会看到来自程序的问候. 注意: 这个例子无法在基于 web 的指南用户界面运行.为了尝试编写 web 服务器,可能

用C写一个web服务器(二) I/O多路复用之epoll

.container { margin-right: auto; margin-left: auto; padding-left: 15px; padding-right: 15px } .container::before,.container::after { content: " "; display: table } .container::after { clear: both } .container::before,.container::after { content:

构建高效安全的Nginx Web服务器

一 一.为什么选择Nginx搭建Web服务器 Apache和Nginx是目前使用最火的两种Web服务器,Apache出现比Nginx早. Apache HTTP Server(简称Apache)是世界使用排名第一的Web服务器软件, 音译为阿帕奇,是Apache软件基金会的一个开放源码Web服务器, 可以运行几乎所有的计算机平台,其次开放的API接口, 任何组织和个人都可以在它上面扩展和增加各种需要功能,达到为自己量身定制的功能. Nginx("engine x")是一个高性能的HTT

关于Web服务器的认识

马上就要毕业了,也要开始找工作了,大学写了这么多代码了,却没有好好总结一下常用的概念很是遗憾额,就通过这篇博客记录一下我最常用的一些知识好了. 说到Web服务器,有很多文章都介绍的很好,之前看到一篇非常不错的,对我帮助很大,可惜现在找不到原文了,看到博客园有人转载,我就在这里也记一下好了,在此非常感谢作者的分析,受益匪浅. 那么在说Web服务器之前,先说说线程.进程.以及并发连接数. 1.进程与线程 进程是具有一定独立功能的程序,关于某个数据集合上的一次运行活动,进程是系统进行资源分配和调度的一

Tinywebserver:一个简易的web服务器

这是学习网络编程后写的一个练手的小程序,可以帮助复习I/O模型,epoll使用,线程池,HTTP协议等内容. 程序代码是基于<Linux高性能服务器编程>一书编写的. 首先回顾程序中的核心内容和主要问题,最后给出相关代码. 0. 功能和I/O模型 实现简易的HTTP服务端,现仅支持GET方法,通过浏览器访问可以返回相应内容. I/O模型采用Reactor(I/O复用 + 非阻塞I/O) + 线程池. 使用epoll事件循环用作事件通知,如果listenfd上可读,则调用accept,把新建的f

Nginx 0.8.x + PHP 5.2.13(FastCGI)搭建胜过Apache十倍的Web服务器

[文章作者:张宴 本文版本:v6.3 最后修改:2010.07.26 转载请注明原文链接:http://blog.zyan.cc/nginx_php_v6/] 前言:本文是我撰写的关于搭建“Nginx + PHP(FastCGI)”Web服务器的第6篇文章.本系列文章作为国内最早详细介绍 Nginx + PHP 安装.配置.使用的资料之一,为推动 Nginx 在国内的发展产生了积极的作用.本文可能不断更新小版本,请记住原文链接“http://blog.zyan.cc/nginx_php_v6/”

Nginx 0.8.x + PHP 5.2.13(FastCGI)搭建胜过Apache十倍的Web服务器(第6版)

前言:本文是我撰写的关于搭建“Nginx + PHP(FastCGI)”Web服务器的第6篇文章.本系列文章作为国内最早详细介绍 Nginx + PHP 安装.配置.使用的资料之一,为推动 Nginx 在国内的发展产生了积极的作用.本文可能不断更新小版本,请记住原文链接“http://blog.zyan.cc/nginx_php_v6/”,获取最新内容.第6篇文章主要介绍了Nginx 0.8.x新的平滑重启方式,将PHP升级到了5.2.14,修正了PEAR问题.另将MySQL 5.1.x升级到了