import threading
import socket
import logging
import selectors
logging.basicConfig(format='%(thread)s %(threadName)s %(message)s', level=logging.INFO)
class ChatServer:
def __init__(self,ip='127.0.0.1',port=9990):
self.sock = socket.socket()
self.addr = (ip,port)
self.event = threading.Event()
self.clients = {}
self.selector = selectors.DefaultSelector()
def start(self):
self.sock.bind(self.addr)
self.sock.listen()
#threading.Thread(target=self._accept,name='accept',daemon=True).start()
self.sock.setblocking(False)
key = self.selector.register(self.sock,selectors.EVENT_READ,self._accept)
threading.Thread(target=self._run,name='run',daemon=True).start()
def _run(self):
while not self.event.is_set():
events = self.selector.select()
for key,mask in events:
callback = key.data
callback(key.fileobj,mask)
def stop(self):
self.event.set()
self.fobjs = []
for fobj,key in self.selector.get_map().items():
key.fileobj.close() #关闭conn监视 和recv监视
self.fobjs.append(fobj)
for x in self.fobjs:
self.selector.unregister(x)
self.selector.close() #关闭socket
def _accept(self,sock:socket.socket,mask):
conn,client = self.sock.accept()
self.clients[client] = conn
conn.setblocking(False)
#threading.Thread(target=self._recv,args=(conn,client),name='recv').start()
self.selector.register(conn,selectors.EVENT_READ,self._recv)
def _recv(self,conn,mask):
data = conn.recv(1024).decode()
print(data)
data = data.strip()
msg = 'ack {}\n'.format(data)
for key in self.selector.get_map().values():
if key.data == self._recv:
key.fileobj.send(msg.encode())
def main():
cs = ChatServer()
cs.start()
e = threading.Event()
while not e.wait(1):
cmd = input('>>>>').strip()
if cmd == 'quit':
cs.stop()
e.wait(3)
break
if __name__ == '__main__':
main()
运行结果:
>>>>hello
quit
quit
改进:
import threading
import socket
import logging
import selectors
import queue
logging.basicConfig(format='%(thread)s %(threadName)s %(message)s', level=logging.INFO)
class Conn:
def __init__(self,conn,handle):
self.queue = queue.Queue()
self.conn = conn
self.handle = handle
class ChatServer:
def __init__(self,ip='127.0.0.1',port=9991):
self.sock = socket.socket()
self.addr = (ip,port)
self.event = threading.Event()
self.clients = {}
self.selector = selectors.DefaultSelector()
self.queue = queue.Queue()
def start(self):
self.sock.bind(self.addr)
self.sock.listen()
self.sock.setblocking(False)
key = self.selector.register(self.sock,selectors.EVENT_READ,self._accept)
threading.Thread(target=self._run,name='run',daemon=True).start()
def _run(self):
while not self.event.is_set():
events = self.selector.select()
for key,mask in events:
if callable(key.data):
callback = key.data
else:
callback = key.data.handle
callback(key.fileobj,mask)
def stop(self):
self.event.set()
self.fobjs = []
for fobj,key in self.selector.get_map().items():
key.fileobj.close() #关闭conn监视 和recv监视
self.fobjs.append(fobj)
for x in self.fobjs:
self.selector.unregister(x)
self.selector.close() #关闭socket
def _accept(self,sock:socket.socket,mask):
conn,client = self.sock.accept()
self.clients[client] = Conn(conn,self._handle)
conn.setblocking(False)
self.selector.register(conn,selectors.EVENT_READ | selectors.EVENT_WRITE,self.clients[client])
def _handle(self,conn,mask):
if mask & selectors.EVENT_READ == selectors.EVENT_READ:
data = conn.recv(1024).decode()
print(data)
data = data.strip()
msg = 'ack {}\n'.format(data)
for c in self.clients.values():
c.queue.put(msg.encode())
if mask & selectors.EVENT_WRITE == selectors.EVENT_WRITE:
remote = conn.getpeername()
client = self.clients[remote]
while not client.queue.empty():
msg = client.queue.get()
conn.send(msg)
def main():
cs = ChatServer()
cs.start()
e = threading.Event()
while not e.wait(1):
cmd = input('>>>>').strip()
if cmd == 'quit':
cs.stop()
e.wait(3)
break
if __name__ == '__main__':
main()
运行结果:
>>>>hello
python
quit
quit
Process finished with exit code 0