zoukankan      html  css  js  c++  java
  • IO多路复用

     内容回顾:

    第一阶段:
    socket, 服务端同时只处理一个请求
    第二阶段:
    select + socket, 实现伪并发
    a. r_list : 即读又写
    b. r_list, w_list 读写分离
    第三阶段:
    socketserver
    select / epoll + socket +多线程
    并发操作

    IO多路复用:通过一种机制,可以监视多个描述符(文件句柄,对象的标识符, 定位文件数据在内存中位置),一旦某个描述符就绪(一般是读就绪或者写就绪),能够通知程序进行相应的读写操作。

    Python中select模块,提供:select、poll、epoll三个方法,分别调用系统的 select,poll,epoll 从而实现IO多路复用。

    基于select实现多路复用功能:

    server端:
    import socket sk1 = socket.socket() sk1.bind(("127.0.0.1",8001,)) sk1.listen() sk2 = socket.socket() sk2.bind(("127.0.0.1",8002,)) sk2.listen() sk3 = socket.socket() sk3.bind(("127.0.0.1",8003,)) sk3.listen() inputs = [sk1,sk2,sk3] import select while True: #sk1,sk2, select在内部自动监听多个对象 #如果有人连接 sk1 #r_list = [sk1,sk2],第一个inputs:如果对象发生变化就放到r_list里, #中间的参数传了什么:w_list就是什么,不会变动 #第三个inputs:如果谁发生错误就放到e_list里面 r_list,w_list,e_list = select.select(inputs,[sk1,sk2,],inputs,1)#1为等待时间 for sk in r_list: #每一个连接对象 conn,address = sk.accept() conn.sendall(bytes("hello",encoding="utf-8")) conn.close() for sk in e_list: inputs.remove(sk)#谁出错就把谁去掉 clint端1: import socket obj = socket.socket() obj.connect(("127.0.0.1",8001,)) connent = str(obj.recv(1024), encoding="utf-8") print(connent) obj.close() clint端2: import socket obj = socket.socket() obj.connect(("127.0.0.1",8002,)) connent = str(obj.recv(1024), encoding="utf-8") print(connent) obj.close()

    完整的server端和client端示例(伪并发)

    实现了一个server,其功能就是可以和多个client建立连接,每个client的发过来的数据加上一个response字符串返回给client端~~~

    server端:
    import socket
    import select
    
    sk = socket.socket()
    sk.bind(('127.0.0.1', 9000),)
    sk.listen(5)
    
    inputs = [sk, ]
    outputs = []
    message = {}  # 实现读写分离
    print("start...")
    
    while True:
        # 监听的inputs中的socket对象内部如果有变化,那么这个对象就会在rlist
        # outputs里有什么对象,wlist中就有什么对象
        # []如果这里的对象内部出错,那会把这些对象加到elist中
        # 1 是超时时间
        rlist, wlist, elist = select.select(inputs, outputs, [], 1)
        print(len(inputs), len(outputs))
    
        for r in rlist:
            if r == sk:
                conn, addr = sk.accept()
                conn.sendall(b"ok")
                # 这里记住是吧conn添加到inputs中去监听,千万别写成r了
                inputs.append(conn)
                message[conn] = []
            else:
                try:
                    data = r.recv(1024)
                    print(data)
                    if not data:
                        raise Exception('连接断开')
                    message[r].append(data)
                    outputs.append(r)
                except Exception as e:
                    inputs.remove(r)
                    del message[r]
    
        for r in wlist:
            data = str(message[r].pop(), encoding='utf-8')
            res = data + "response"
            r.sendall(bytes(res, encoding='utf-8'))
            outputs.remove(r)
    # 实现读写分离
    # IO多路复用的本质是用select、poll、epoll(系统底层提供的)来监听socket对象内部是否有变化
    # select 是在Win和Linux中都支持额,相当于系统内部维护了一个for循环,缺点是监听个数有上限(1024),效率不高
    # poll的监听个数没有限制,但仍然用循环,效率不高。
    # epoll的机制是socket对象变化,主动告诉epoll。而不是轮询,相当于有个回调函数,效率比前两者高
    # Nginx就是用epoll。只要IO操作都支持,除开文件操作
    
    # 列表删除指定元素用remove
    
    
    clint端:
    import socket
    sc = socket.socket()
    sc.connect(("127.0.0.1", 9000,))
    
    data = sc.recv(1024)
    print(data)
    while True:
        msg = input(">>>:")
        if msg == 'q':
            break
        if len(msg) == 0:
            continue
    
        send_msg = bytes(msg, encoding="utf-8")
        sc.send(send_msg)
        res = sc.recv(1024)
        print(str(res, encoding="utf-8"))
    sc.close()

    线程:

    import threading
    import time
    def process(arges):
        time.sleep(1)
        print(arges)
    
    #轮循
    # for i in range(10):
    #     process(i)
    
    #创建10个线程,一次执行这10个
    for i in range(10):
       t = threading.Thread(target=process, args=(i,))#创建线程,每创建一个线程让一个方法去执行它
       t.start()

    进程

    协程

    成产者消费模型

  • 相关阅读:
    10.28
    10.29
    11.05周四
    数据库增删改查
    11.03Tuesday
    11.10
    连接数据库
    10.30
    11.04周三
    10.27
  • 原文地址:https://www.cnblogs.com/zcok168/p/9276889.html
Copyright © 2011-2022 走看看