Python32 Socket Serv
- 2020 年 1 月 6 日
- 筆記
類型
- socketserver有幾種類型: class socketserver.TCPServer:用於TCP class socketserver.UDPServer:用於UDP class socketserver.UnixStreamServer:用於Unix的TCP class socketserver.UnixDatagramServer:用於Unix的UDP

TCPServer繼承了BaseServer UnixStreamServer繼承了TCPServer
- 創建socket server至少分以下幾步: 1、必須創建一個請求處理類,並且這個類要繼承BaseRequestHandler,還要重寫父類里的handle方法(跟客戶端所有的交互都是在handle中寫的)。 2、必須要實例化一個協議server(如TCPServer),並且傳遞server ip和你上面創建的請求處理類,給這個TCPServer(實例化的時候將IP和請求處理類傳給TCPServer)。 3、然後可以根據上面的實例來處理請求: server.handle_request() #只處理一個請求 server.handle_forever() #處理多個請求,永遠執行(一般都是用這個) 4、調用server_close()去關閉
server端: import socketserver class MyTCPHandler(socketserver.BaseRequestHandler): '''第1步:創建處理類,繼承Base。 客戶端每一次請求過來都會實例化這個類''' def handle(self): '''第1步:重寫handle方法,handle默認存在父類中程式碼是空的。 客戶端所有交互都在handle中完成''' while True: #使其可以循環發送數據 self.data = self.request.recv(1024).decode().strip() #這裡的self.request.recv相當於之前用的conn.recv print ("{} wrote:".format(self.client_address[0])) #列印客戶端的IP地址資訊 print (self.data) #列印數據資訊 self.request.send(self.data.upper().encode('utf-8')) #傳回數據給客戶端,只是upper了一下 #sendall就是重複調用send if __name__ == "__main__": HOST,PORT = "localhost",9999 server = socketserver.TCPServer((HOST,PORT),MyTCPHandler) #第2步:實例化TCPServer,並將IP和MyTCPHandler當做參數傳給請求處理類 #監聽客戶端的每一個請求,就會實例化MyTCPHandler這個類,拿MyTCPHandler的handle與客戶端交互。 server.serve_forever() #第3步:允許永遠處理多個請求 client端: import socket client = socket.socket() client.connect(('localhost',9999)) while True: msg = input(">>:").strip() if len(msg) == 0:continue client.send(msg.encode('utf-8')) data = client.recv(1024) print ("recv:",data.decode()) client.close() client執行結果: >>:abc recv: ABC >>:efg recv: EFG >>:hhh recv: HHH >>: server執行結果: 127.0.0.1 wrote: abc 127.0.0.1 wrote: efg 127.0.0.1 wrote: hhh client斷開後server報錯: ---------------------------------------- Exception happened during processing of request from ('127.0.0.1', 53933) Traceback (most recent call last): File "D:python37libsocketserver.py", line 313, in _handle_request_noblock self.process_request(request, client_address) File "D:python37libsocketserver.py", line 344, in process_request self.finish_request(request, client_address) File "D:python37libsocketserver.py", line 357, in finish_request self.RequestHandlerClass(request, client_address, self) File "D:python37libsocketserver.py", line 712, in __init__ self.handle() File "E:/python/程式碼練習/A2.py", line 11, in handle self.data = self.request.recv(1024).decode().strip() ConnectionResetError: [WinError 10054] 遠程主機強迫關閉了一個現有的連接。 ---------------------------------------- #可以看到這裡報錯ConnectionResetError: [WinError 10054]
修改server端: import socketserver class MyTCPHandler(socketserver.BaseRequestHandler): def handle(self): while True: #使其可以循環發送數據 try: #使用try的話就不需要使用 if not data的方式來判斷客戶端斷開時,無數據的情況了 self.data = self.request.recv(1024).decode().strip() #這裡的self.request.recv相當於之前用的conn.recv print ("{} wrote:".format(self.client_address[0])) print (self.data) self.request.send(self.data.upper().encode('utf-8')) except ConnectionResetError as e: print ("err:",e) break #這裡一定要break,不然就會一直死循環 if __name__ == "__main__": HOST,PORT = "localhost",9999 server = socketserver.TCPServer((HOST,PORT),MyTCPHandler) server.serve_forever() server執行結果: 127.0.0.1 wrote: abc 127.0.0.1 wrote: 123 err: [WinError 10054] 遠程主機強迫關閉了一個現有的連接。 #客戶端斷開連接後,就通過斷言的方式抓到錯誤了。
上面的程式碼目前還不能支援多並發,如果有多個並發,後面的並發就會被掛起; 如果要並發的話,需要修改一下程式碼。

通過ctrl點TCPServer

可以看到TCPServer是繼承了BaseServer

修改server端: import socketserver class MyTCPHandler(socketserver.BaseRequestHandler): def handle(self): while True: #使其可以循環發送數據 try: #使用try的話就不需要使用 if not data的方式來判斷客戶端斷開時,無數據的情況了 self.data = self.request.recv(1024).decode().strip() print ("{} wrote:".format(self.client_address[0])) print (self.data) self.request.send(self.data.upper().encode('utf-8')) except ConnectionResetError as e: print ("err:",e) break if __name__ == "__main__": HOST,PORT = "localhost",9999 server = socketserver.ThreadingTCPServer((HOST,PORT),MyTCPHandler) # 上面的程式碼需要使用ThreadingTCPServer server.serve_forever() client 1執行結果: >>:test 1 recv: TEST 1 >>: client 2執行結果: >>:test 2 recv: TEST 2 >>: client 3執行結果: >>:test 3 recv: TEST 3 >>: server 執行結果: 127.0.0.1 wrote: test 1 127.0.0.1 wrote: test 2 127.0.0.1 wrote: test 3

可以看到server端現在支援多並發,沒有被掛起;每來一個請求會開啟一個新執行緒與server交互;每個執行緒都是獨立的,10個執行緒,就可以做10件事情。
通過ctrl點ThreadingTCPServer

可以看到將TCPServer這個類傳了進去 同時還傳了ThreadingMixIn;TCPServer是負責與客戶端交互,而多執行緒都是由ThreadingMixIn實現的。
ctrl點ThreadingMixIn

這部分就是多執行緒的主要程式碼