Python编程之基础知识练习_007

练习内容:socket,IO多路复用,Python selectors库,实现简单的群聊。

1.服务端代码

 1 __author__ = 'Orcsir'
 2 import selectors
 3 import threading
 4 import socket
 5 from collections import namedtuple
 6 
 7 
 8 class ChatServer:
 9     def __init__(self, ip="0.0.0.0", port=9527):
10         self.addr = (ip, port)
11         self.sock = socket.socket()
12         self.selector = selectors.DefaultSelector()
13         self.data = namedtuple("data", ["callback", "datagram"])
14 
15     def start(self):
16         self.sock.bind(self.addr)
17         self.sock.listen()
18         self.sock.setblocking(False)
19         self.selector.register(self.sock, selectors.EVENT_READ, self.data(self.accept, b""))
20         threading.Thread(target=self.select, name="select").start()
21 
22     def select(self):
23         while True:
24             try:
25                 events = self.selector.select()
26             except:
27                 self.stop()
28                 return
29 
30             for key, mask in events:
31                 data = key.data
32                 callback = data.callback
33                 datagram = data.datagram
34                 callback(key.fileobj, mask, datagram)
35 
36     def accept(self, sock: socket.socket, mask, data):
37         conn, raddr = sock.accept()
38         conn.setblocking(False)
39         self.selector.register(conn, selectors.EVENT_READ | selectors.EVENT_WRITE, self.data(self.recv_send, data))
40 
41     # 处理数据接收
42     def _process_recv(self, conn: socket.socket, mask):
43         try:
44             data = conn.recv(1024)
45         except:
46             self.selector.unregister(conn)
47             conn.close()
48             return
49 
50         if data:
51             for key in self.selector.get_map().values():
52                 if key.fileobj != self.sock:
53                     datagram = "From {}. Contents: {}".format(conn.getpeername(), data.decode()).encode()
54                     self.selector.modify(key.fileobj, selectors.EVENT_WRITE, self.data(self.recv_send, datagram))
55         else:
56             self.selector.unregister(conn)
57             conn.close()
58 
59     # 处理数据发送
60     def _process_send(self, conn: socket.socket, mask, datagram: bytes):
61         conn.send(datagram)
62         self.selector.modify(conn, selectors.EVENT_READ, self.data(self.recv_send, b""))
63 
64     # 分发函数
65     def recv_send(self, conn: socket.socket, mask, datagram: bytes):
66         if mask & selectors.EVENT_READ:
67             self._process_recv(conn, mask)
68         elif mask & selectors.EVENT_WRITE:
69             self._process_send(conn, mask, datagram)
70 
71     def stop(self):
72         connects = []
73         if self.selector.get_map():
74             for key in self.selector.get_map().values():
75                 connects.append(key.fileobj)
76 
77         for conn in connects:
78             self.selector.unregister(conn)
79             conn.close()
80         self.selector.close()
81 
82 
83 if __name__ == '__main__':
84     cs = ChatServer()
85     cs.start()
86     while True:
87         cmd = input(">>>")
88         if cmd.strip() == "quit":
89             cs.stop()
90             break

2.客户端代码

 1 __author__ = 'Orcsir'
 2 
 3 import socket
 4 import threading
 5 import logging
 6 
 7 FORMAT = "%(message)s"
 8 logging.basicConfig(format=FORMAT, level=logging.INFO)
 9 
10 
11 class ChatClient:
12     def __init__(self, ip="127.0.0.1", port=9527):
13         self.sock = socket.socket()
14         self.raddr = (ip, port)
15 
16     def start(self):
17         self.sock.connect(self.raddr)
18         threading.Thread(target=self._recv, name="recv").start()
19 
20     def _recv(self):
21         while True:
22             try:
23                 data = self.sock.recv(1024)
24             except:
25                 self.sock.close()
26                 return
27             if data:
28                 logging.info("recv: {}".format(data.decode()))
29             else:
30                 self.sock.close()
31                 return
32 
33     def send(self, data: str):
34         self.sock.send(data.encode())
35 
36     def stop(self):
37         if self.sock:
38             self.sock.close()
39 
40 
41 def main():
42     cc = ChatClient()
43     cc.start()
44     while True:
45         cmd = input(">>>")
46         if cmd.strip() == "quit":
47             cc.stop()
48             return
49         cc.send(cmd)
50 
51 main()

3.启动两个ipython模拟客户端

猜你喜欢

转载自www.cnblogs.com/orcsir/p/9191672.html