实用: python中IO多路复用实现简单echo服务器(selectors)

import selectors
import socket
import threading
import myutils


def recv(conn:socket.socket):
    data = conn.recv(1024).strip().decode()
    print(data)
    msg = 'Your msg = {}\n'.format(data)
    conn.send(msg.encode())

def accept(sock:socket.socket):
    conn,client = sock.accept()
    conn.setblocking(False)

    selector.register(conn,selectors.EVENT_READ,recv)


#创建监听socket对象
sock = socket.socket()
ip = '127.0.0.1'
port = 9990
addr = (ip,port)
sock.bind(addr)
sock.listen()
sock.setblocking(False)

#平台自适应
selector = selectors.DefaultSelector()
key = selector.register(sock,selectors.EVENT_READ, accept)
#SelectorKey(fileobj=如下, fd=4, events=1, data=<function accept at 0x7f5ad883f268>)
#fileobj=<socket.socket fd=4, family=AddressFamily.AF_INET, type=2049, proto=0, laddr=('127.0.0.1', 9990)>
print(key)#四元组

myutils.showthreads()

e = threading.Event()

while not e.is_set():
    events = selector.select()
    if events:
        print('`````````',events)#列表,列表元素为二元组,二元组的元素由一个四元组和1-3数字组成

    for key,mask in events:
        print('=========',key,mask)
        callback = key.data
        callback(key.fileobj)

额外自定义模块myutils的代码如下:

import threading,logging
logging.basicConfig(level=logging.INFO)
e = threading.Event()
def showthreads():
    def _showthread():
        while not e.wait(5):
            logging.info(threading.enumerate())
    threading.Thread(target=_showthread,daemon=True).start()

在这里插入图片描述
运行结果:

SelectorKey(fileobj=<socket.socket fd=3, family=AddressFamily.AF_INET, type=2049, proto=0, laddr=('127.0.0.1', 9990)>, fd=3, events=1, data=<function accept at 0x7f5801bc09d8>)
`````````[(SelectorKey(fileobj=<socket.socket fd=3, family=AddressFamily.AF_INET, type=2049, proto=0, laddr=('127.0.0.1', 9990)>, fd=3, events=1, data=<function accept at 0x7f5801bc09d8>), 1)]
========= SelectorKey(fileobj=<socket.socket fd=3, family=AddressFamily.AF_INET, type=2049, proto=0, laddr=('127.0.0.1', 9990)>, fd=3, events=1, data=<function accept at 0x7f5801bc09d8>) 1
INFO:root:[<_MainThread(MainThread, started 140015987357440)>, <Thread(Thread-1, started daemon 140015962216192)>]
`````````[(SelectorKey(fileobj=<socket.socket fd=5, family=AddressFamily.AF_INET, type=2049, proto=0, laddr=('127.0.0.1', 9990), raddr=('127.0.0.1', 53582)>, fd=5, events=1, data=<function recv at 0x7f5803191268>), 1)]
========= SelectorKey(fileobj=<socket.socket fd=5, family=AddressFamily.AF_INET, type=2049, proto=0, laddr=('127.0.0.1', 9990), raddr=('127.0.0.1', 53582)>, fd=5, events=1, data=<function recv at 0x7f5803191268>) 1
hello
INFO:root:[<_MainThread(MainThread, started 140015987357440)>, <Thread(Thread-1, started daemon 140015962216192)>]

改进:

import selectors
import socket
import threading

# 平台自适应
selector = selectors.DefaultSelector()

def recv(conn: socket.socket,mask):
    data = conn.recv(1024).strip().decode()
    print(data)
    msg = 'Your msg = {}\n'.format(data)
    conn.send(msg.encode())


def accept(sock: socket.socket,mask):
    conn, client = sock.accept()
    conn.setblocking(False)

    selector.register(conn, selectors.EVENT_READ, recv)


# 创建监听socket对象
sock = socket.socket()
ip = '127.0.0.1'
port = 9990
addr = (ip, port)
sock.bind(addr)
sock.listen()
sock.setblocking(False)
key = selector.register(sock, selectors.EVENT_READ, accept)
# SelectorKey(fileobj=如下, fd=4, events=1, data=<function accept at 0x7f5ad883f268>)
# fileobj=<socket.socket fd=4, family=AddressFamily.AF_INET, type=2049, proto=0, laddr=('127.0.0.1', 9990)>
print(key)  # 四元组


e = threading.Event()

def work(event:threading.Event):
    while not e.is_set():
        events = selector.select()
        if events:
            print('1,event = {}'.format(events))

        for key,mask in events:
            callback = key.data
            callback(key.fileobj,mask)


threading.Thread(target=work,name='work',args=(e,)).start()

while not e.is_set():
    cmd = input('>>>>')
    if cmd.strip() == 'quit':
        e.set()
        fobjs = []
        print(2,selector.get_map().items())
        for fobj,key in selector.get_map().items():
            print(3,fobj,key)
            print(4,key.fileobj)
            key.fileobj.close()
            fobjs.append(fobj)

        for x in fobjs: #实际x为文件描述符
            selector.unregister(x)

        selector.close()

在这里插入图片描述
运行结果:

SelectorKey(fileobj=<socket.socket fd=4, family=AddressFamily.AF_INET, type=2049, proto=0, laddr=('127.0.0.1', 9990)>, fd=4, events=1, data=<function accept at 0x7f565d170b70>)
>>>>1,event = [(SelectorKey(fileobj=<socket.socket fd=4, family=AddressFamily.AF_INET, type=2049, proto=0, laddr=('127.0.0.1', 9990)>, fd=4, events=1, data=<function accept at 0x7f565d170b70>), 1)]
1,event = [(SelectorKey(fileobj=<socket.socket fd=5, family=AddressFamily.AF_INET, type=2049, proto=0, laddr=('127.0.0.1', 9990), raddr=('127.0.0.1', 54248)>, fd=5, events=1, data=<function recv at 0x7f565e6c7268>), 1)]
hello
quit
2 ItemsView(<selectors._SelectorMapping object at 0x7f565e6d8c18>)
3 4 SelectorKey(fileobj=<socket.socket fd=4, family=AddressFamily.AF_INET, type=2049, proto=0, laddr=('127.0.0.1', 9990)>, fd=4, events=1, data=<function accept at 0x7f565d170b70>)
4 <socket.socket fd=4, family=AddressFamily.AF_INET, type=2049, proto=0, laddr=('127.0.0.1', 9990)>
3 5 SelectorKey(fileobj=<socket.socket fd=5, family=AddressFamily.AF_INET, type=2049, proto=0, laddr=('127.0.0.1', 9990), raddr=('127.0.0.1', 54248)>, fd=5, events=1, data=<function recv at 0x7f565e6c7268>)
4 <socket.socket fd=5, family=AddressFamily.AF_INET, type=2049, proto=0, laddr=('127.0.0.1', 9990), raddr=('127.0.0.1', 54248)>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值