手寫微信羣聊服務器

需求分析

1. 可以鏈接多個客戶端;socket

2. 客戶端長時間未響應可以斷開節省資源;ui

3. 可以羣發,一個用戶發來一條消息,全部客戶端均可以接收;spa

 

思路

直接使用socket.socket類就能夠實現,可是這樣的話咱們須要本身手動寫監聽,寫accept,把accept單獨放入一個線程,每連入一個線程就新開闢一個線程。線程

 

這裏咱們選用socketserver這個庫來實現,這樣咱們只須要把核心步驟寫出來便可,其餘的都能自動化幫咱們完成了。code

 1 mport socketserver
 2 import datetime
 3 import threading
 4 
 5 
 6 class MyHandle(socketserver.BaseRequestHandler):  # 每個線程就一個實例
 7     def self_server_init(self):
 8         if not hasattr(self.server, "clients"):
 9             setattr(self.server, "clients", {})  # 若是沒有這個屬性就給他增長一個
10         if not hasattr(self.server, "_lock_clients"):
11             setattr(self.server, "lock_clients", threading.Lock())
12         self.server.__dict__["hb_interval"] = 10
13         self.server.clients[self.key] = datetime.datetime.now().timestamp()  # 記錄時間
14 
15     def setup(self):
16         # self init
17         self.event = threading.Event()
18         self.key = self.request, self.event
19         # self.server init
20         self.self_server_init()
21 
22     def handle(self):
23         no_hb = set()
24         while not self.event.is_set():
25             data = self.request.recv(1024)
26             print(data.decode())
27             if data == b"^hb^":   # 收到了心跳包
28                 with self.server.lock_clients:
29                     self.server.clients[self.key] = datetime.datetime.now().timestamp()
30             if data == b"" or data.strip() == b"quit":
31                 with self.server.lock_clients:
32                     self.server.clients.pop(self.key, None)  # 若是退出就彈出了
33                 break  # 由於一個線程是一個鏈接
34 
35             # 若是沒有退出咱們就刷新時間,也有多是新的鏈接
36             self.server.clients[self.key] = datetime.datetime.now().timestamp()
37 
38             # 發送消息的時候檢查是否超時了
39             with self.server.lock_clients:
40                 for key, t in self.server.clients.items():
41                     if datetime.datetime.now().timestamp() - t > self.server.hb_interval:  # 若是超時了記錄一下這個key
42                         no_hb.add(key)  # s和e均可哈希
43                         continue
44                     key[0].send("from {}: {}".format(self.client_address, data.decode()).encode())
45                 for key in no_hb:
46                     self.server.clients.pop(key)  # 移除沒有心跳的客戶端
47                 no_hb.clear()
48 
49     def finish(self):
50         super().finish()
51         self.event.set()
52 
53 
54 server = socketserver.ThreadingTCPServer(("127.0.0.1", 9999), MyHandle)
55 server.serve_forever()   # 啓動
相關文章
相關標籤/搜索