python 关于epoll的学习
2015-10-28 15:51
471 查看
在linux中,默认情况下所有的socket都是blocking;当
用户进程调用了recvfrom这个系统调用,kernel就开始了IO的第一个阶段:准备数据。对于network
io来说,很多时候数据在一开始还没有到达(比如,还没有收到一个完整的UDP包),这个时候kernel就要等待足够的数据到来。而在用户进程这边,整
个进程会被阻塞。当kernel一直等到数据准备好了,它就会将数据从kernel中拷贝到用户内存,然后kernel返回结果,用户进程才解除
block的状态,重新运行起来。
所以,blocking IO的特点就是在IO执行的两个阶段(等待数据和拷贝数据两个阶段)都被block了。
几乎所有的程序员第一次接触到的网络编程都是从listen()、send()、recv() 等接口开始的,这些接口都是阻塞型的。使用这些接口可以很方便的构建服务器/客户机的模型。
在python socket模型当中,当使用socket初次编程的时候都会遇到一个阻塞问题;当一个socet的server被一个client暂用之后;参数了阻塞,新的连接是不能进来的,当然还有一个封装的socketserver利用多线程很好的解决了这个问题;但是我们思考一个问题,就是当连接数很多时候很多的线程是否对我们系统照成影响呢,当然可以通过线程池来解决这个问题,但是瓶颈也会产生。
下面学习用epoll的方式来进行网络编程,当然对比与select只能打开1024(可以调整,但是文件描述符多了性能会下降)epoll的优势就非常明显了。
代码:
#!/usr/bin/env python # -*- coding: utf-8 -*- import socket, select import Queue,os serversocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) serversocket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) server_address = ("", 8999) serversocket.bind(server_address) serversocket.listen(1) print "服务器启动成功,监听IP:" , server_address serversocket.setblocking(0) #设置成非阻塞时间 timeout = 10 #新建epoll事件对象,后续要监控的事件添加到其中 epoll = select.epoll() #注册服务器监听fd到等待读事件集合 epoll.register(serversocket.fileno(), select.EPOLLIN) message_queues = {} fd_to_socket = {serversocket.fileno():serversocket,} while True: # print "等待活动连接......" #轮询注册的事件集合 events = epoll.poll(timeout) # if not events: # print "epoll超时无活动连接,重新轮询......" # continue # print "有" , len(events), "个新事件,开始处理......" for fd, event in events: socket = fd_to_socket[fd] #可读事件 if event & select.EPOLLIN: #如果活动socket为服务器所监听,有新连接 if socket == serversocket: connection, address = serversocket.accept() print "新连接:" , address connection.setblocking(0) #注册新连接fd到待读事件集合 epoll.register(connection.fileno(), select.EPOLLIN) fd_to_socket[connection.fileno()] = connection message_queues[connection] = Queue.Queue() #否则为客户端发送的数据 else: data = socket.recv(1024) if data: print "收到数据:" , data , "客户端:" , socket.getpeername() message_queues[socket].put(data) #修改读取到消息的连接到等待写事件集合 epoll.modify(fd, select.EPOLLOUT) #可写事件 elif event & select.EPOLLOUT: try: msg = message_queues[socket].get_nowait() xiaoluo = os.popen(msg).read() except Queue.Empty: print socket.getpeername() , " queue empty" epoll.modify(fd, select.EPOLLIN) else : print "发送数据:" , data , "客户端:" , socket.getpeername() socket.send(xiaoluo) #关闭事件 elif event & select.EPOLLHUP: epoll.unregister(fd) fd_to_socket[fd].close() del fd_to_socket[fd] epoll.unregister(serversocket.fileno()) epoll.close() serversocket.close()这样就实现了无阻塞的io SOcket模型:
可以参考老外写的文章:
http://scotdoyle.com/python-epoll-howto.html
相关文章推荐
- python 关于epoll的学习
- python下的socket学习,包括select, epoll,kqueue
- 关于Python语法、正则表达式的学习
- python关于argparse模块的学习内容
- 关于python的学习
- python语言学习——关于全局
- Python学习笔记(六)关于日期的一些操作
- 【Python学习笔记】关于if __name__ == '__main__'
- Python面向对象编程中关于类和方法的学习笔记
- 关于python元组的一些学习心得
- 30. Python脚本学习笔记三十 更多关于SWIG
- 创业日记-关于学习Python
- python 学习(二)--关于类
- Python的学习笔记DAY7---关于爬虫(2)之Scrapy初探
- 关于python struct模块的性能问题-----待学习
- python笔记(1) 关于我们应不应该继续学习python
- Python学习笔记(四) 关于dictionary遍历
- 关于python中九九乘法表的小白学习心得
- python爬虫学习(1)--关于正则表达式输入和提取中文
- Go学习笔记 - 关于Java、Python、Go编程思想的不同