實用: 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)>
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章