1. IO多路复用
    import asyncio 这个是异步IO模块 这个还不知道怎么用
  2.  
  3. select poll epoll 都是IO多路复用
  4.  
  5. windows 仅支持select
  6.  
  7. linux2.6以后 支持epoll epoll是相当厉害的
  8.  
  9. 详细的描述参考:http://www.cnblogs.com/alex3714/articles/5876749.html
  10.  
  11. selectpollepoll区别:http://www.cnblogs.com/alex3714/p/4372426.html
  12.  
  13. 先来写一个用select方式的socket模型
  1. import select #引入select模块,这是利用操作系统的select处理方式,windows、linux、unix都支持
  2. import socket
  3. import sys
  4. import queue
  5.  
  6. server = socket.socket()
  7. server.setblocking(0)
  8.  
  9. server_addr = ('0.0.0.0',9999)
  10.  
  11. print('starting up on %s port %s' % server_addr)
  12. server.bind(server_addr)
  13.  
  14. server.listen(5)
  15.  
  16. inputs = [server, ] #自己也要监测呀,因为server本身也是个fd
  17. outputs = []
  18.  
  19. message_queues = {}
  20.  
  21. while True:
  22. print("waiting for next event...")
  23.  
  24. readable, writeable, exeptional = select.select(inputs,outputs,inputs) #如果没有任何fd就绪,那程序就会一直阻塞在这里
  25.  
  26. for s in readable: #每个s就是一个socket
  27.  
  28. if s is server: #别忘记,上面我们server自己也当做一个fd放在了inputs列表里,传给了select,如果这个s是server,代表server这个fd就绪了,
  29. #就是有活动了, 什么情况下它才有活动? 当然 是有新连接进来的时候 呀
  30. #新连接进来了,接受这个连接
  31. conn, client_addr = s.accept()
  32. print("new connection from",client_addr)
  33. conn.setblocking(0)
  34. inputs.append(conn) #为了不阻塞整个程序,我们不会立刻在这里开始接收客户端发来的数据, 把它放到inputs里, 下一次loop时,这个新连接
  35. #就会被交给select去监听,如果这个连接的客户端发来了数据 ,那这个连接的fd在server端就会变成就续的,select就会把这个连接返回,返回到
  36. #readable 列表里,然后你就可以loop readable列表,取出这个连接,开始接收数据了, 下面就是这么干 的
  37.  
  38. message_queues[conn] = queue.Queue() #接收到客户端的数据后,不立刻返回 ,暂存在队列里,以后发送
  39.  
  40. else: #s不是server的话,那就只能是一个 与客户端建立的连接的fd了
  41. #客户端的数据过来了,在这接收
  42. try:
  43. data = s.recv(1024)
  44. except ConnectionResetError as e:
  45. data=None
  46. print(e)
  47. print("客户端断开了", s)
  48. if s in outputs:
  49. outputs.remove(s) # 清理已断开的连接
  50. inputs.remove(s) # 清理已断开的连接
  51. del message_queues[s] ##清理已断开的连接
  52. if data:
  53. print("收到来自[%s]的数据:" % s.getpeername()[0], data)
  54. message_queues[s].put(data) #收到的数据先放到queue里,一会返回给客户端
  55. if s not in outputs:
  56. outputs.append(s) #为了不影响处理与其它客户端的连接 , 这里不立刻返回数据给客户端
  57.  
  58. else:#如果收不到data代表什么呢? 代表客户端断开了呀
  59. print("客户端断开了",s)
  60.  
  61. if s in outputs:
  62. outputs.remove(s) #清理已断开的连接
  63. if s in inputs:
  64. inputs.remove(s) #清理已断开的连接
  65. if s in message_queues.keys():
  66. del message_queues[s] ##清理已断开的连接
  67.  
  68. for s in writeable:
  69. try :
  70. next_msg = message_queues[s].get_nowait()
  71.  
  72. except queue.Empty:
  73. print("client [%s]" %s.getpeername()[0], "queue is empty..")
  74. outputs.remove(s)
  75.  
  76. else:
  77. print("sending msg to [%s]"%s.getpeername()[0], next_msg)
  78. s.send(next_msg.upper())
  79.  
  80. for s in exeptional:
  81. print("handling exception for ",s.getpeername())
  82. inputs.remove(s)
  83. if s in outputs:
  84. outputs.remove(s)
  85. s.close()
  86.  
  87. del message_queues[s]

再来一个升级版本的,selectors模块,它底层是看操作系统的,默认是epoll,但是如果不支持,比如windows,linux kernel < 2.6,就用select模式

  1. import selectors,socket #selectors 超牛的IO多路复用的模块,支持select poll epoll ,优先epoll
  2.  
  3. sel=selectors.DefaultSelector()
  4.  
  5. def accpect(sock,mask): #创建业务连接的方法
  6. conn,addr=sock.accept()
  7. print("accept:",conn,"from:",addr)
  8. conn.setblocking(False)
  9. sel.register(fileobj=conn,events=selectors.EVENT_READ,data=read)
  10.  
  11. def read(conn,mask): #连接以后 执行业务的方法
  12. data=conn.recv(1024)
  13. if data:
  14. print("recv data:",data,"conn:",conn)
  15. # print(conn.getsockname())
  16. conn.send(data)
  17. else:
  18. print("close:",conn)
  19. sel.unregister(fileobj=conn)
  20. conn.close()
  21.  
  22. server=socket.socket()
  23. server.bind(("0.0.0.0",9999))
  24. server.listen(10000)
  25. server.setblocking(False)
  26.  
  27. sel.register(fileobj=server,events=selectors.EVENT_READ,data=accpect) #只需要注册需要并发使用IO的应用,明确对应的回调data内容就行了
  28.  
  29. while True:
  30. events=sel.select()
  31. print("已经注册sel数量:")
  32. for key,mask in events:
  33. callback=key.data #获取注册时的sel.register()方法参数中的data对应的内容,之前放进去的有accpect和read函数
  34. callback(key.fileobj,mask)

这里注意,有个非常非常尴尬的问题情景:

需求:

1、基于socket

2、要多进程处理业务(多线程由于GIL锁,多核也无法真正同时刻处理,所以用多进程)

3、进程内必须是selectors处理连接

此时,就非常尴尬了,原因是多进程multiprocessing模块,IO多路复用selectors模块,他俩有矛盾:

矛盾就是:

multiprocessing就是认为socket是阻塞的,

selectors要求socket必须是非阻塞的,不然没办法监听活动。

那么socket怎么办呢,这个问题,在windows还好,因为select方式还是慢,显不出来,linux epoll超快的,直接就严重影响业务了

我是这么解决这个矛盾的

需要多次接收或发送 或者 循环发送循环接收的业务情景,selectors监听到后,步骤:

1、从selectors实例中注销掉这个业务连接,

2、设定这个业务连接为阻塞,

3、开始进行上述情景业务,

4、再设定为非阻塞,

5、重新注册回selectors

python3.x Day6 IO多路复用的更多相关文章

  1. socket_server源码剖析、python作用域、IO多路复用

    本节内容: 课前准备知识: 函数嵌套函数的使用方法: 我们在使用函数嵌套函数的时候,是学习装饰器的时候,出现过,由一个函数返回值是一个函数体情况. 我们在使用函数嵌套函数的时候,最好也这么写. def ...

  2. python运维开发(十)----IO多路复用线程基本使用

    内容目录: python作用域 python2.7和python3.5的多继承区别 IO多路复用 socketserver模块源分析 多线程.进程.协程 python作用域  python中无块级作用 ...

  3. Python实战之IO多路复用select的详细简单练习

    IO多路复用 I/O多路复用指:通过一种机制,可以监视多个描述符,一旦某个描述符就绪(一般是读就绪或者写就绪),能够通知程序进行相应的读写操作. select   它通过一个select()系统调用来 ...

  4. IO模式和IO多路复用

    网络编程里常听到阻塞IO.非阻塞IO.同步IO.异步IO等概念,总听别人装13不如自己下来钻研一下.不过,搞清楚这些概念之前,还得先回顾一些基础的概念. 1 基础知识回顾 注意:咱们下面说的都是Lin ...

  5. 转载 io多路复用

    作者:ZingpLiu 出处:http://www.cnblogs.com/zingp/ 本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接. 回到 ...

  6. IO模式和IO多路复用详解

    网络编程里常听到阻塞IO.非阻塞IO.同步IO.异步IO等概念,总听别人装13不如自己下来钻研一下.不过,搞清楚这些概念之前,还得先回顾一些基础的概念. 1 基础知识回顾 注意:咱们下面说的都是Lin ...

  7. epoll——IO多路复用选择器

    上上篇博客讲的套接字,由于其阻塞性而导致一个服务端同一时间只能与一个客户端连接.基于这个缺点,在上篇博客我们将其设置为非阻塞实现了一个服务端同一时间可以与多个客户端相连,即实现了并发,但其同样留下了一 ...

  8. 网络编程socket 结合IO多路复用select; epool机制分别实现单线程并发TCP服务器

    select版-TCP服务器 1. select 原理 在多路复用的模型中,比较常用的有select模型和epoll模型.这两个都是系统接口,由操作系统提供.当然,Python的select模块进行了 ...

  9. Python(七)Socket编程、IO多路复用、SocketServer

    本章内容: Socket IO多路复用(select) SocketServer 模块(ThreadingTCPServer源码剖析) Socket socket通常也称作"套接字" ...

随机推荐

  1. P5168 xtq玩魔塔

    传送门 其实就是板子--只要会克鲁斯卡尔重构树和带修莫队就可以了 这么想着的我就调了将近一个下午-- 思路其实比较清晰,然而码量很大,细节贼多-- 不难看出只在最小生成树上走最优,于是建出克鲁斯卡尔重 ...

  2. git 项目切换分支 命令

    在项目开发总,一般都会用到git管理工具,有的公司可能还是用的svn:不管怎么样.用的顺手就行: 来说下git 的基本使用 git clone + 项目地址链接: 可以把项目克隆到本地: 然后一般顺序 ...

  3. USACO Training3.1联系【排序终极题目】By cellur925

    题目传送门 这题我们很容易想到直接枚举即可.算法本身并没有什么难度但是细节超多!于是这题整整卡了一天....... (不,还是我太弱了.) 期间还暴露出一些平时没有特别注意的问题,这次一起解决. 开始 ...

  4. Linux下tcp服务器创建的步骤

    创建一个socket,使用函数socket() socket(套接字)实质上提供了进程通信的端点,进程通信之前,双方首先必须建立各自的一个端点,否则没有办法通信.通过socket将IP地址和端口绑定之 ...

  5. iOS WKWebView 退出后停止播放音频/视频

    带有<video>或者<audio>标签的H5网页在播放音频视频时,退出webview后不会自动停止播放,手动处理一下. 1.注入使网页停止音频.视频播放的JS代码(Swift ...

  6. 使用ansible对远程主机上的ssh公钥进行批量分发

    使用ansible对远程主机上的ssh公钥进行批量分发或者是删除修改操作 ansible内置了一个authorized_key模块,这个模块很好用,我们使用这个模块可以对远程 主机上的ssh公钥进行批 ...

  7. solrJ的查询->统计【转】

    package com.fjsh.SearchJobsFirst; import java.text.SimpleDateFormat; import java.util.Calendar; impo ...

  8. 取URL中各个参数的值

    取参数值的方法有很多,个人记录一个方便好用的 //查询参数(参数名)function GetQueryString(name) {    var reg = new RegExp("(^|& ...

  9. repeater使用

    Repeater: HeaderTemplate - 在加载开始执行一遍 ItemTemplate - 有多少条数据,执行多少遍 FooterTemplate - 在加载最后执行一遍 Alternat ...

  10. Mac上面不能安装Homebrew

    这个stackoverflow的答案解决了我的问题: http://stackoverflow.com/questions/18039029/mac-can-t-install-homebrew 问题 ...