zoukankan      html  css  js  c++  java
  • python自动化开发学习 I/O多路复用

    python自动化开发学习 I/O多路复用

     

    一. 简介

      socketserver在内部是由I/O多路复用,多线程和多进程,实现了并发通信。IO多路复用的系统消耗很小。

    IO多路复用底层就是监听socket对象内部是否有变化,是否在收发消息,Python中select模块提供了select poll epoll 三种方式来实现IO多路复用,支持不同的操作系统。

      windows : 提供select

      Mac : 提供select

      Linux : 提供select, poll, epoll

    (1)select简介:

      select 默认会将每一个变化的socket加入一个他自己维护的列表中,但是并不会明确是哪一个socket,它内部其实是通过一个for循环遍历整个列表,当列表中的socket很多的时候,for循环就会浪费资源。select默认可以监听1024个链接,它是由linux在同文件中定义的,可修改。select不是安全的线程,如果你把一个socket加入到select中,突然另外一个线程关闭了这个socket,那么接下来select的行为是随机的。

    (2)poll简介:

      poll修复了select的一些问题,例如去掉了1024个链接限制,想要监听多少都可以,poll不在修改传入的数组,但是poll依然不是线程安全的。

    (3)epoll简介:

      epoll不仅会告诉你socket组里面的数据,还会告诉你具体哪个socket有数据,无需自己寻找。而且epoll终于是线程安全的了。然而epoll局限于

    Linux操作系统。

    二 . 应用

    select 方法

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    句柄列表11, 句柄列表22, 句柄列表33 = select.select(句柄序列1, 句柄序列2, 句柄序列3, 超时时间)<br>
    参数: 可接受四个参数(前三个必须)
    返回值:三个列表
       
    select方法用来监视文件句柄,如果句柄发生变化,则获取该句柄。
    1、当 参数1 序列中的句柄发生可读时(accetp和read),则获取发生变化的句柄并添加到 返回值1 序列中
    2、当 参数2 序列中含有句柄时,则将该序列中所有的句柄添加到 返回值2 序列中
    3、当 参数3 序列中的句柄发生错误时,则将该发生错误的句柄添加到 返回值3 序列中
    4、当 超时时间 未设置,则select会一直阻塞,直到监听的句柄发生变化
       当 超时时间 = 1时,那么如果监听的句柄均无任何变化,则select会阻塞 1 秒,之后返回三个空列表,如果监听的句柄有变化,则直接执行。

    (1)监听客户端连接

     服务端

    import socket
    import select

    sk = socket.socket()
    sk.bind(("127.0.0.1", 9999,))
    sk.listen(5)

    while True:
    rlist, w, e = select.select([sk, ], [], [], 5)
    # 监听sk(服务器端)对象,如果sk对象发生变化,表示有客户端来连接了,此时rlist值为[sk]
    # 监听conn对象,如果conn发生变化,表示客户端有消息发送过来了,此时rlist的值为[客户端]
    print(rlist)

    for r in rlist:
    print(r)
    conn, address = r.accept()
    conn.sendall(bytes("hello", encoding="utf-8"))

    服务端

     客户端

    import socket

    sk = socket.socket()
    sk.connect(("127.0.0.1", 9999,))

    data = sk.recv(1024)
    print(data)

    while True:
    input(">>")

    sk.close()

    客户端

    (2)监听客户端连接及接受客户端发送的数据

     服务端

    import socket
    import select

    sk = socket.socket()
    sk.bind(("127.0.0.1", 9999,))
    sk.listen(5)


    inputs = [sk,]
    while True:
    rlist, w, e = select.select(inputs, [], [], 1)
    # 监听sk(服务器端)对象,如果sk对象发生变化,表示有客户端来连接了,此时rlist值为[sk]
    # 监听conn对象,如果conn发生变化,表示客户端有消息发送过来了,此时rlist的值为[客户端]

    print(len(inputs), len(rlist))

    for r in rlist:
    print(r)
    if r == sk:
    # 有新的客户端连接进来
    conn, address = r.accept()
    inputs.append(conn)
    conn.sendall(bytes("hello", encoding="utf-8"))
    else:
    # 有客户端给我发送数据
    recv_data = r.recv(1024)
    print(recv_data)

    服务端

     客户端

    import socket

    sk = socket.socket()
    sk.connect(("127.0.0.1", 9999,))

    data = sk.recv(1024)
    print(data)

    while True:
    inp = input(">>")
    sk.sendall(bytes(inp, encoding='utf-8'))

    sk.close()

    客户端

    (3)读写分离

     服务端

    import socket
    import select

    sk = socket.socket()
    sk.bind(("127.0.0.1", 9999,))
    sk.listen(5)


    inputs = [sk,]
    outputs = []

    while True:
    rlist, wlist, e = select.select(inputs, outputs, [], 1)
    # 监听sk(服务器端)对象,如果sk对象发生变化,表示有客户端来连接了,此时rlist值为[sk]
    # 监听conn对象,如果conn发生变化,表示客户端有消息发送过来了,此时rlist的值为[客户端]

    print(len(inputs), len(rlist))

    for r in rlist:
    print(r)
    if r == sk:
    # 有新的客户端连接进来
    conn, address = r.accept()
    inputs.append(conn)
    conn.sendall(bytes("hello", encoding="utf-8"))
    else:
    # 有客户端给我发送数据
    try:
    recv_data = r.recv(1024)

    if not recv_data: # 某些操作系统,在socket断开的时候,会发送一个空给server,所以要判断空的情况
    raise Exception("断开连接")
    else:
    outputs.append(r)
    except Exception as e:
    inputs.remove(r)

    for w in wlist:
    w.sendall(bytes("response", encoding="utf-8"))
    outputs.remove(w)

    服务端

     客户端

    import socket

    sk = socket.socket()
    sk.connect(("127.0.0.1", 9999,))

    data = sk.recv(1024)
    print(data)

    while True:
    inp = input(">>")
    sk.sendall(bytes(inp, encoding='utf-8'))
    print(sk.recv(1024))
    sk.close()

    客户端

    (4)读写分离之服务端根据客户端的输入返回对应的信息

     服务端

    import socket
    import select

    sk = socket.socket()
    sk.bind(("127.0.0.1", 9999,))
    sk.listen(5)


    inputs = [sk, ] #
    outputs = []
    messages = {} # 用来存放客户端发送过来的消息,存放格式 连接客户端的对象: 消息

    while True:
    rlist, wlist, elist = select.select(inputs, outputs, [sk, ], 1)
    # rlist 监听sk(服务器端)对象,如果sk对象发生变化,表示有客户端来连接了,此时rlist值为[sk]
    # wlist 监听conn对象,如果conn发生变化,表示客户端有消息发送过来了,此时rlist的值为[客户端]
    # elist 监听sk(服务器端)对象是否发生错误

    print(len(inputs), len(rlist))

    for r in rlist:
    print(r)
    if r == sk:
    # 有新的客户端连接进来
    conn, address = r.accept()
    inputs.append(conn)
    messages[conn] = [] # 在存储消息的字典中创建一个以客户端连接对象为key 空列表为value的键值对
    conn.sendall(bytes("hello", encoding="utf-8"))
    else:
    # 有客户端给我发送数据
    try:
    recv_data = r.recv(1024)

    if not recv_data: # 某些操作系统,在socket断开的时候,会发送一个空给server,所以要判断空的情况
    raise Exception("断开连接")
    else:
    outputs.append(r)
    messages[r].append(recv_data)

    except Exception as e:
    inputs.remove(r)
    del messages[r]

    for w in wlist:
    print(messages[w])
    msg = messages[w].pop()
    resp = msg + bytes("response", encoding="utf-8")
    w.sendall(resp)
    outputs.remove(w)

    服务端

     客户端

    import socket

    sk = socket.socket()
    sk.connect(("127.0.0.1", 9999,))

    data = sk.recv(1024)
    print(data)

    while True:
    inp = input(">>")
    sk.sendall(bytes(inp, encoding='utf-8'))
    print(sk.recv(1024))
    sk.close()

    客户端

      

  • 相关阅读:
    numpy 基础 —— np.linalg
    图像旋转后显示不完全
    opencv ---getRotationMatrix2D函数
    PS1--cannot be loaded because the execution of scripts is disabled on this system
    打开jnlp Faild to validate certificate, the application will not be executed.
    BATCH(BAT批处理命令语法)
    oracle vm virtualbox 如何让虚拟机可以上网
    merge 实现
    Windows batch,echo到文件不成功,只打印出ECHO is on.
    python2.7.6 , setuptools pip install, 报错:UnicodeDecodeError:'ascii' codec can't decode byte
  • 原文地址:https://www.cnblogs.com/meng-wei-zhi/p/8258848.html
Copyright © 2011-2022 走看看