转一贴,今天实在写累了,也看累了--【Python异步非阻塞IO多路复用Select/Poll/Epoll使用】
下面这篇,原理理解了,
再结合 这一周来的心得体会,整个框架就差不多了。。。
http://www.haiyun.me/archives/1056.html
有许多封装好的异步非阻塞IO多路复用框架,底层在linux基于最新的epoll实现,为了更好的使用,了解其底层原理还是有必要的。
下面记录下分别基于Select/Poll/Epoll的echo server实现。
Python Select Server,可监控事件数量有限制:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
|
#!/usr/bin/python# -*- coding: utf-8 -*-import selectimport socketimport Queue server = socket.socket(socket.AF_INET,socket.SOCK_STREAM)server.setblocking(False)server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR , 1)server_address= ('192.168.1.5',8080)server.bind(server_address)server.listen(10) #select轮询等待读socket集合inputs = [server]#select轮询等待写socket集合outputs = []message_queues = {}#select超时时间timeout = 20 while True: print "等待活动连接......" readable , writable , exceptional = select.select(inputs, outputs, inputs, timeout) if not (readable or writable or exceptional) : print "select超时无活动连接,重新select...... " continue; #循环可读事件 for s in readable : #如果是server监听的socket if s is server: #同意连接 connection, client_address = s.accept() print "新连接: ", client_address connection.setblocking(0) #将连接加入到select可读事件队列 inputs.append(connection) #新建连接为key的字典,写回读取到的消息 message_queues[connection] = Queue.Queue() else: #不是本机监听就是客户端发来的消息 data = s.recv(1024) if data : print "收到数据:" , data , "客户端:",s.getpeername() message_queues[s].put(data) if s not in outputs: #将读取到的socket加入到可写事件队列 outputs.append(s) else: #空白消息,关闭连接 print "关闭连接:", client_address if s in outputs : outputs.remove(s) inputs.remove(s) s.close() del message_queues[s] for s in writable: try: msg = message_queues[s].get_nowait() except Queue.Empty: print "连接:" , s.getpeername() , '消息队列为空' outputs.remove(s) else: print "发送数据:" , msg , "到", s.getpeername() s.send(msg) for s in exceptional: print "异常连接:", s.getpeername() inputs.remove(s) if s in outputs: outputs.remove(s) s.close() del message_queues[s] |
Python Poll Server,Select升级版,无可监控事件数量限制,还是要轮询所有事件:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
|
#!/usr/bin/python# -*- coding: utf-8 -*-import socketimport selectimport Queue server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)server.setblocking(False)server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)server_address = ("192.168.1.5", 8080)server.bind(server_address)server.listen(5)print "服务器启动成功,监听IP:" , server_addressmessage_queues = {}#超时,毫秒timeout = 5000#监听哪些事件READ_ONLY = ( select.POLLIN | select.POLLPRI | select.POLLHUP | select.POLLERR)READ_WRITE = (READ_ONLY|select.POLLOUT)#新建轮询事件对象poller = select.poll()#注册本机监听socket到等待可读事件事件集合poller.register(server,READ_ONLY)#文件描述符到socket映射fd_to_socket = {server.fileno():server,}while True: print "等待活动连接......" #轮询注册的事件集合 events = poller.poll(timeout) if not events: print "poll超时,无活动连接,重新poll......" continue print "有" , len(events), "个新事件,开始处理......" for fd ,flag in events: s = fd_to_socket[fd] #可读事件 if flag & (select.POLLIN | select.POLLPRI) : if s is server : #如果socket是监听的server代表有新连接 connection , client_address = s.accept() print "新连接:" , client_address connection.setblocking(False) fd_to_socket[connection.fileno()] = connection #加入到等待读事件集合 poller.register(connection,READ_ONLY) message_queues[connection] = Queue.Queue() else : #接收客户端发送的数据 data = s.recv(1024) if data: print "收到数据:" , data , "客户端:" , s.getpeername() message_queues[s].put(data) #修改读取到消息的连接到等待写事件集合 poller.modify(s,READ_WRITE) else : # Close the connection print " closing" , s.getpeername() # Stop listening for input on the connection poller.unregister(s) s.close() del message_queues[s] #连接关闭事件 elif flag & select.POLLHUP : print " Closing ", s.getpeername() ,"(HUP)" poller.unregister(s) s.close() #可写事件 elif flag & select.POLLOUT : try: msg = message_queues[s].get_nowait() except Queue.Empty: print s.getpeername() , " queue empty" poller.modify(s,READ_ONLY) else : print "发送数据:" , data , "客户端:" , s.getpeername() s.send(msg) #异常事件 elif flag & select.POLLERR: print " exception on" , s.getpeername() poller.unregister(s) s.close() del message_queues[s] |
Python Epoll Server,基于回调的事件通知模式,轻松管理大量连接:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
|
#!/usr/bin/python# -*- coding: utf-8 -*-import socket, selectimport Queueserversocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)serversocket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)server_address = ("192.168.1.5", 8080)serversocket.bind(server_address)serversocket.listen(1)print "服务器启动成功,监听IP:" , server_addressserversocket.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() except Queue.Empty: print socket.getpeername() , " queue empty" epoll.modify(fd, select.EPOLLIN) else : print "发送数据:" , data , "客户端:" , socket.getpeername() socket.send(msg) #关闭事件 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() |
转一贴,今天实在写累了,也看累了--【Python异步非阻塞IO多路复用Select/Poll/Epoll使用】的更多相关文章
- [转]让你从零开始学会写爬虫的5个教程(Python)
让你从零开始学会写爬虫的5个教程(Python) 写爬虫总是非常吸引IT学习者,毕竟光听起来就很酷炫极客,我也知道很多人学完基础知识之后,第一个项目开发就是自己写一个爬虫玩玩. 其实懂了之后,写个 ...
- 写给非专业人士看的 *** 简介(同时也解释了GFW )
写给非专业人士看的 *** 简介 这个文章来源于一个朋友在***的过程中,搞不清楚 *** 的配置问题,在这里我想按照我对 *** 的理解简单梳理一下,以便一些非专业人士也能了解 long long ...
- openpyxl -用于读/写Excel 2010 XLSX/XLSM文件的python库
openpyxl -用于读/写Excel 2010 XLSX/XLSM文件的python库¶ https://www.osgeo.cn/openpyxl/index.html
- 如果公司里有上百个表要做触发器,如果手动写代码的话。很累,所以今天写了一个小程序,自动生成mysql的触发代码。
<?php $dbname = 'test';//数据库 $tab1 = 'user'; //执行的表 $tab2 = 'user_bak'; //被触发的表 $conn = mysql_con ...
- SpringBoot写后端接口,看这一篇就够了!
摘要:本文演示如何构建起一个优秀的后端接口体系,体系构建好了自然就有了规范,同时再构建新的后端接口也会十分轻松. 一个后端接口大致分为四个部分组成:接口地址(url).接口请求方式(get.post等 ...
- 让你从零开始学会写爬虫的5个教程(Python)
写爬虫总是非常吸引IT学习者,毕竟光听起来就很酷炫极客,我也知道很多人学完基础知识之后,第一个项目开发就是自己写一个爬虫玩玩. 其实懂了之后,写个爬虫脚本是很简单的,但是对于新手来说却并不是那么容易. ...
- [python]新手写爬虫v2.5(使用代理的异步爬虫)
开始 开篇:爬代理ip v2.0(未完待续),实现了获取代理ips,并把这些代理持久化(存在本地).同时使用的是tornado的HTTPClient的库爬取内容. 中篇:开篇主要是获取代理ip:中篇打 ...
- (转)新手写爬虫v2.5(使用代理的异步爬虫)
开始 开篇:爬代理ip v2.0(未完待续),实现了获取代理ips,并把这些代理持久化(存在本地).同时使用的是tornado的HTTPClient的库爬取内容. 中篇:开篇主要是获取代理ip:中篇打 ...
- 新手教程:不写JS,在MIP页中实现异步加载数据
从需求谈起:在 MIP 页中异步加载数据 MIP(移动网页加速器) 的 加速原理 除了靠谱的 MIP-Cache CDN 加速外,最值得一提的就是组件系统.所有 JS 交互都需要使用 MIP 组件实现 ...
随机推荐
- CentOS 7.x安装ELK(Elasticsearch+Logstash+Kibana)
第一次听到ELK,是新浪的@ARGV 介绍内部使用ELK的情况和场景,当时触动很大,原来有那么方便的方式来收集日志和展现,有了这样的工具,你干完坏事,删除日志,就已经没啥作用了. 很多企业都表示出他们 ...
- MVC 表单提交提示:已添加了具有相同键的项。
MVC:页面提交的时候报如下错误: 解决方案: 这个Model 里面定义了重复的字段so~~~
- angularjs开发总结
使用AngularJS有差不多一年时间了,前前后后也用了不少库和指令,整理了一下,分成四大类列出.有demo地址的,就直接连接到demo地址,其它的直接链到github托管库中. 图片视频类 angu ...
- 数据库字段出现科学计数法e+的情况分析
问题: 有时候,我们在将excel表格中数据导入数据库中时,对于表格中的数字会默认为float的数据类型,这个时候导入到数据库中的这个表的值是正常显示的: 然而如果你要把导入到数据库中的表,再插入到另 ...
- jquery实现asp.net 网页鼠标所在位置
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="mouseposition. ...
- [DP] LGTB 玩THD (复杂状态DP)
LGTB 玩THD LGTB 最近在玩一个类似DOTA 的游戏名叫THD有一天他在守一座塔,对面的N 个小兵排成一列从近到远站在塔前面每个小兵有一定的血量hi,杀死后有一定的金钱gi每一秒,他都可以攻 ...
- 生产者-消费者模型的3种Java实现:synchronized,signal/notifyAll及BlockingQueue
我的技术博客经常被流氓网站恶意爬取转载.请移步原文:http://www.cnblogs.com/hamhog/p/3555111.html,享受整齐的排版.有效的链接.正确的代码缩进.更好的阅读体验 ...
- 浅析JAVA设计模式(一)
第一写技术博客,只是想把自己一天天积累的东西与大家分享.今天在看<大型网站架构和java中间件>这本书时,其中提到代理模式的动态代理.作为java中间件的一个重要基础,我觉的有必要整理和分 ...
- select框默认样式去除(ie中隐藏默认下拉图标)
html代码 <select class="info-select"> <option selected="selected">1< ...
- iOS极光推送集成步骤
1.下载SDK,导入Xcode 2.在苹果开发者中心建立AppId与bundleID进行关联,注意勾选推送功能 3.在苹果开发者中心建立推送证书 4.在极光后台建立应用且上传推送证书 5.建立描述文件 ...