python select.epoll
2016-03-16 10:58
423 查看
参考:
http://www.360doc.com/content/11/1119/15/2660674_165748138.shtml http://blog.csdn.net/my2010sam/article/details/9877717
http://www.360doc.com/content/11/1119/15/2660674_165748138.shtml http://blog.csdn.net/my2010sam/article/details/9877717
#!/usr/bin/env python ''' epoll实现服务器时,需要用到register()和unregister()方法,作用是加入和移除对象, epoll()的返回值包括了文件描述符和事件, polling的事件常量有 POLLIN,读取数据 POLLPRI,紧急数据 POLLPOUT,文件描述符已经准备好 POLLERR,文件描述符出错 POLLHUP,连接丢失 POLLVAL,无效请求。 epoll 对象操作流程 建立一个epoll对象 告诉epoll对象, 对于一些socket监控一些事件. 问epoll, 从上次查询以来什么socket产生了什么事件. 针对这些socket做特定操作. 告诉epoll, 修改监控socket和/或监控事件. 重复第3步到第5步, 直到结束. 销毁epoll对象. 采用异步socket的时候第3步重复了第2步的事情. 这里的程序更复杂, 因为一个线程需要和多个客户端交互. http://www.360doc.com/content/11/1119/15/2660674_165748138.shtml ''' import socket import select import argparse SERVER_HOST = '' EOL1 = b'\n\n' EOL2 = b'\n\r\n' 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!""" class EpollServer(object): """ A socket server using Epoll""" def __init__(self, host=SERVER_HOST, port=0): self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) self.sock.bind((host, port)) self.sock.listen(5) self.sock.setblocking(0)#设置socket为非阻塞模式 self.sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1) print "Started Epoll Server" self.epoll = select.epoll() #建立一个epoll对象. self.epoll.register(self.sock.fileno(), select.EPOLLIN)#注册服务器socket, 监听读取事件. 服务器socket接收一个连接的时候, 产生一个读取事件. fileno是文件描述符, 是一个整型数. def run(self): """Executes epoll server operation""" try: #connections表映射文件描述符(file descriptors, 整型)到对应的socket对象上面 #requests #responses connections = {}; requests = {}; responses = {} while True: #epoll对象查询一下是否有感兴趣的事件发生, 参数1说明我们最多等待1秒的时间. 如果有对应事件发生, 立刻会返回一个事件列表 events = self.epoll.poll(1) #返回的events是一个(fileno, event code)tuple元组列表. fileno是文件描述符, 是一个整型数. for fileno, event in events: #如果是服务器socket的事件, 那么需要针对新的连接建立一个socket. if fileno == self.sock.fileno(): connection, address = self.sock.accept() connection.setblocking(0)#设置socket为非阻塞模式 self.epoll.register(connection.fileno(), select.EPOLLIN) #注册socket的read(EPOLLIN)事件. connections[connection.fileno()] = connection requests[connection.fileno()] = b'' responses[connection.fileno()] = SERVER_RESPONSE elif event & select.EPOLLIN: #如果读取事件发生, 从客户端读取新数据.(打印client http 请求头) requests[fileno] += connections[fileno].recv(1024) if EOL1 in requests[fileno] or EOL2 in requests[fileno]: #一旦完整的http请求接收到, 取消注册读取事件, 注册写入事件(EPOLLOUT), 写入事件在能够发送数据回客户端的时候产生 self.epoll.modify(fileno, select.EPOLLOUT) #打印完整的http请求, 展示即使通讯是交错的, 数据本身是作为一个完整的信息组合和处理的. print('-'*40 + '\n' + requests[fileno].decode()[:-2]) elif event & select.EPOLLOUT: # 如果写入事件发生在一个客户端socket上面, 我们就可以发送新数据到客户端了. # 一次发送一部分返回数据, 直到所有数据都交给操作系统的发送队列. byteswritten = connections[fileno].send(responses[fileno]) responses[fileno] = responses[fileno][byteswritten:] if len(responses[fileno]) == 0: self.epoll.modify(fileno, 0)#一旦所有的返回数据都发送完, 取消监听读取和写入事件. connections[fileno].shutdown(socket.SHUT_RDWR)#如果连接被明确关闭掉, 这一步是可选的. 这个例子采用这个方法是为了让客户端首先断开, 告诉客户端没有数据需要发送和接收了, 然后让客户端断开连接. elif event & select.EPOLLHUP:#HUP(hang-up)事件表示客户端断开了连接(比如 closed), 所以服务器这端也会断开. 不需要注册HUP事件, 因为它们都会标示到注册在epoll的socket. self.epoll.unregister(fileno) connections[fileno].close() del connections[fileno] finally: #在这里的异常捕捉的作用是, 我们的例子总是采用键盘中断来停止程序执行. #虽然开启的socket不需要手动关闭, 程序退出的时候会自动关闭, 明确写出来这样的代码, 是更好的编码风格. self.epoll.unregister(self.sock.fileno()) self.epoll.close() self.sock.close() if __name__ == '__main__': parser = argparse.ArgumentParser(description='Socket Server Example with Epoll') parser.add_argument('--port', action="store", dest="port", type=int, required=True) given_args = parser.parse_args() port = given_args.port server = EpollServer(host=SERVER_HOST, port=port) server.run()
相关文章推荐
- python进阶学习笔记(一):打开文件
- batch downloading file in python
- 插入排序
- julia与python中的列表解析.jl
- python学习笔记(7)-高级特性(三)-列表生成式与生成器
- python学习笔记(6)-高级特性(二)-迭代
- think python学习心得-(1)关于函数和模块
- windows系统中python2,python3共存的设置方法
- Python,pymysql简单使用。
- python中去掉HTML空格和全角Unicode空格
- python资料汇总
- python中的re.sub replace strip
- Python 图片下载PictureSpider
- pip安装使用详解
- Python项目自动化部署最佳实践@搜狐 | the5fire的技术博客
- Python学习心得之lxml的安装之路
- Python中的GIL
- 针对格式文件,Python读取一定大小的文件内容
- 安装scrapy时遇到的问题
- 利用python进行数据分析之绘图和可视化