zoukankan      html  css  js  c++  java
  • Python网络编程:IO多路复用

    io多路复用:可以监听多个文件描述符(socket对象)(文件句柄),一旦文件句柄出现变化,即可感知。

      1 sk1 = socket.socket()
      2 sk1.bind(('127.0.0.1',8001))
      3 sk1.listen()
      4 
      5 # sk2 = socket.socket()
      6 # sk2.bind(('127.0.0.1',8002))
      7 # sk2.listen()
      8 while True:
      9     conn,address = sk.accept()#阻塞等待客户端连接、连接、客户端地址信息
     10     print(conn,address)
     11     conn.sendall(bytes('北京欢迎你',encoding='utf-8'))
     12     while True:
     13         ret_bytes = conn.recv(1024)
     14         ret_str = str(ret_bytes,encoding='utf-8')
     15         if ret_str == 'q':
     16             break
     17         conn.sendall(bytes(ret_str+'好',encoding='utf-8'))
     18     print(address,conn)
     19 

    sk1sk2就叫作文件描述符、文件句柄。上面的程序只能执行sk1。

    IO多路复用有一种机制,可以接受多个文件描述符,一旦有谁变化了,就处理。

      1 import socket
      2 sk1 = socket.socket()
      3 sk1.bind(('127.0.0.1',8001))
      4 sk1.listen()
      5 
      6 sk2 = socket.socket()
      7 sk2.bind(('127.0.0.1',8002))
      8 sk2.listen()
      9 
     10 sk3 = socket.socket()
     11 sk3.bind(('127.0.0.1',8002))
     12 sk3.listen()
     13 
     14 inputs = [sk1,sk2]
     15 #本例是用select伪装成多处理用户连接请求,比socket的好处在于不用等待? 难点在于inputs里两类socket,客户端socket和服务端socket?
     16 import select
     17 while True:
     18     #[sk1,sk2,],select内部自动监听sk1,sk2,sk3三个对象,一旦某个句柄发生变化,就会将其放到r_list里。第一次发生变化是sk.accept(),即有人来连sk1.则r_list = [sk1]
     19     r_list,w_list,e_list = select.select(inputs,outputs,inputs,1)#等一秒看是否有人来连接,没有的话执行下一次循环。最多等待的时间。
     20     print('正在监听的socket对象%d' % len(inputs))
     21     print(r_list)
     22     for sk1_or_conn in r_list:
     23 

    IO多路复用是操作系统底层提供的功能,我们只是用Python去调用它,分三种方式,select,poll,epoll。windows只支持select.

    select底层实现原理:

    系统内部c语言进行for循环检测,当文件句柄发送变化的时候告诉我们。性能较低,并且只支持最多1024个文件描述符。


    所以后来就有了poll,对于文件描述符个数没限制了,但底层也是用for循环实现的。

    之后又出现了epoll,底层就不用for循环了,而是用异步实现的,把句柄都放进去,谁有变化了谁主动告诉epoll,而不是for循环一遍遍监测。所以epoll的性能是最高的。

    Nginx的内部就是socket结合epoll来监听用户请求的。

    for sk in e_list:  #e_list是发生错误的文件描述符列表

        inputs.remove(sk)


      1 import socket
      2 sk1 = socket.socket()
      3 sk1.bind(('127.0.0.1',8001))
      4 sk1.listen()
      5 
      6 # sk2 = socket.socket()
      7 # sk2.bind(('127.0.0.1',8002))
      8 # sk2.listen()
      9 #
     10 # sk3 = socket.socket()
     11 # sk3.bind(('127.0.0.1',8003))
     12 # sk3.listen()
     13 inputs = [sk1]
     14 outputs = []
     15 #本例是用select伪装成多处理用户连接请求,比socket的好处在于不用等待? 难点在于inputs里两类socket,客户端socket和服务端socket。
     16 import select
     17 while True:
     18     #[sk1,sk2,],select内部自动监听sk1,sk2,sk3三个对象,一旦某个句柄发生变化
     19     r_list,w_list,e_list = select.select(inputs,outputs,inputs,1)
     20     print('正在监听的socket对象%d' % len(inputs))
     21     print(r_list)
     22     for sk1_or_conn in r_list:
     23         #每一个连接对象
     24         if sk1_or_conn == sk1:
     25             #表示有新用户来连接
     26             conn, address = sk1_or_conn.accept()
     27             inputs.append(conn)
     28         else:
     29             #有老用户发消息了
     30             try:
     31                 data_bytes = sk1_or_conn.recv(1024)
     32             except Exception as ex:
     33                 #如果用户中断连接
     34                 inputs.remove(sk1_or_conn)
     35             else:
     36                 #用户正常发消息
     37                 # data_str = str(data_bytes,encoding='utf-8')
     38                 # sk1_or_conn.sendall(bytes(data_str+'好',encoding = 'utf-8'))
     39                 outputs.append(sk1_or_conn)
     40 #w_list仅仅存谁给我发过消息,如果想读写分离就会用到这个参数
     41     for conn in w_list:
     42         conn.sendall(bytes('hello',encoding='utf-8'))
     43         outputs.remove(conn)
     44 
    IO多路复用处理多用户请求

    上面的难点在于要理解r_list其实并不等于inputs.

    inputs里面两类数据,一类是服务端的socket sk1,另一类是客户端的socket(只要有人来连接就apend一个socket对象)

    而r_list里面存的是发生变化的对象,多个用户来连sk1,r_list里就是sk1,而有用户发消息,那r_list里就变为发消息的socket对象其。


    socketserver:
    select/epoll + socket +多线程实现并发操作。

  • 相关阅读:
    zookeeper使用场景
    zookeeper安装配置
    hadoop 远程调试
    deep learning笔记
    Sentiment Analysis(1)-Dependency Tree-based Sentiment Classification using CRFs with Hidden Variables
    PRML阅读笔记 introduction
    Python 学习笔记(2)
    python nltk 学习笔记(5) Learning to Classify Text
    python nltk 学习笔记(4) Writing Structured Programs
    python nltk 学习笔记(3) processing raw text
  • 原文地址:https://www.cnblogs.com/bolenzhang/p/7197898.html
Copyright © 2011-2022 走看看