python select实现多IO监控

服务器

#使用socket模拟多线程,使多用户可以同时连接
import socket
import select
import queue

sk1 = socket.socket()
sk1.bind(('0.0.0.0', 8001))
sk1.listen()
sk2 = socket.socket()
sk2.bind(('0.0.0.0', 8002))
sk2.listen()
inputs = [sk1, sk2] # 初始监控的对象列表中只有服务器端的socket对象
outputs = []
message_dict = {}

while True:
    r_list, w_list, e_list = select.select(inputs, outputs, inputs, 1) # 第4个参数表示每1秒监控1次
    print('正在监听的socket对象数%d' % len(inputs))
    print(r_list) # 被监控的对象中,发生变化了的对象会被存入r_list列表中,开始运行时,因为没有任何对象发生变化,则为空列表
    for sk1_or_conn in r_list: # 遍历发生了变化的对象
        #每一个连接对象
        if sk1_or_conn in [sk1, sk2]: # 如果发生了变化的对象sk1_or_conn是服务器的socket,表示有新的客户端请求接入
            conn, address = sk1_or_conn.accept() # 与客户端连接,并将客户端socket对象信息存入两个变量中
            conn.setblocking(False) # 设置非阻塞型
            inputs.append(conn) # 将客户端连接对象加入监控列表中,以监控它是否有变化(即监控是否有消息发送过来)
            message_dict[conn] = queue.Queue() # 在消息字典中,建立以客户端为键名的键值对,值初始化为空列队
        else:
            # 如果发生变化的对象sk1_or_conn不是服务器的socket,则表示此时的sk1_or_conn是客户端连接对象 ,即有客户端有消息发送过来了,也或者是客户端断开连接了。
            try:
                data_bytes = sk1_or_conn.recv(1024) # 有消息则接收客户端消息
            except Exception as ex: # 报异常时,表示客户端非正常的终止连接(强行退出)
                inputs.remove(sk1_or_conn) # 如果客户端断开了连接,则将客户端连接从监控列表中移除
                message_dict.pop(sk1_or_conn)
            else: # 没报异常,则将接收到的消息转化为字符,并更新消息字典对应键名的值列表
                if not data_bytes: # 客户端正常退出连接时
                    inputs.remove(sk1_or_conn)
                    message_dict.pop(sk1_or_conn)
                else:
                    data_str = str(data_bytes, encoding='utf-8') # 此为字符转化
                    if sk1_or_conn.getsockname() == ('127.0.0.1', 8001): # 判断客户端连接的是哪个服务器地址,以实现不同的响应
                        data = f'来自sk1:{data_str}'
                        message_dict[sk1_or_conn].put(data) # 此为字典键值的值列队更新
                    else:
                        message_dict[sk1_or_conn].put(f'来自sk2:{data_str}')
                    outputs.append(sk1_or_conn) # 消息接收完后,将客户端连接对象存入准备写消息的监控列表中outputs

    #w_list中仅仅保存了谁给我发过消息
    for conn in w_list: # 遍历写消息的监控列表
        recv_str = message_dict[conn].get_nowait() # 从字典的值列队中取得准备回显的消息
        conn.sendall(bytes(recv_str, encoding='utf-8')) # 将消息回复给客户端
        outputs.remove(conn) # 回复完后就从监控列表中移除,以便准备给下一个回复消息

    for sk in e_list: # 如果有监控列表中有发生异常变化的,该对象会被加入e_list列表中,对它进行遍历
        inputs.remove(sk) # 发生异常即将其从监控列表中移除

 

 

客户端1

import socket

obj = socket.socket()
obj.connect(('127.0.0.1', 8001))

while True:
    inp = input('>>>')
    if inp == "":
        obj.close()
        break
    obj.sendall(bytes(inp, encoding='utf-8'))
    ret = str(obj.recv(1024),encoding='utf-8')
    print(ret)

 

客户端2

 

import socket

obj = socket.socket()
obj.connect(('127.0.0.1', 8002))

while True:
    inp = input('>>>')
    if inp == "":
        obj.close()
        break
    obj.sendall(bytes(inp, encoding='utf-8'))
    ret = str(obj.recv(1024),encoding='utf-8')
    print(ret)

 

posted @ 2021-10-12 20:09  张永谊  阅读(174)  评论(0)    收藏  举报