一、簡介
SocketServer簡化了網絡服務器的編寫。在進行socket創建時,使用SocketServer會大大減少創建的步驟,並且SocketServer使用了select它有5個類:BaseServer,TCPServer,UDPServer,UnixStreamServer,UnixDatagramServer。后4個類是同步進行處理的,另外通過ForkingMixIn和ThreadingMixIn類來支持異步。
SocketServer的5個類的繼承關系
SocketServer內部使用 IO多路復用 以及 “多線程” 和 “多進程” ,從而實現並發處理多個客戶端請求的Socket服務端。即:每個客戶端請求連接到服務器時,Socket服務端都會在服務器是創建一個“線程”或者“進 程” 專門負責處理當前客戶端的所有請求。
二、提供的類型
一是Server類:BaseServer/TCPServer/UDPServer用來接收客戶的請求。TCPServer處理TCP請求,UDPServer處理UDP請求。BaserServer是基類,不能直接使用。TCPServer繼承自BaseServer,UDPServer繼承自TCPServer。
二是Handler類:BaseRequestHandler/DatagramRequestHandler/StreamRequestHandler用來處理每一個客戶請求。一般用使用BaseRequestHandler就行,但StreamRequestHandler/DatagramRequestHandler提供了一些特別的功能,前者用來處理流式(TCP)請求,后者處理數據報(UDP)請求。Server每收到一個客戶請求就會創建一個Handler類示例來處理該請求。默認情況下,TCPServer/UDPServer是單進程單線程的模型,依次處理每個客戶請求,一個請求處理完畢才能接着處理下一個請求。
三是MixIn類:ForkingMixIn/ThreadingMixIn用來為Server提供多進程/多線程並發處理能力的。ForkingMixIn是多進程模型,ThreadingMixin是多線程模型。這里特別巧妙的是,你只要創建一個類,同時繼承Server類和MixIn類就能自動獲得並發處理請求的能力。該模塊本身就直接提供了這種類。
class ForkingUDPServer(ForkingMixIn, UDPServer): pass class ForkingTCPServer(ForkingMixIn, TCPServer): pass class ThreadingUDPServer(ThreadingMixIn, UDPServer): pass class ThreadingTCPServer(ThreadingMixIn, TCPServer): pass三
三、創建socketserver步驟
- 必須先創建一個請求處理的類,並且這個類要繼承BaseRequestHandle,並重寫父類中的handle方法
- 實例化一個server class,並且傳遞server ip 和剛創建的請求處理類給server class
- 調用server class 對象的 handle_request() 或 server_forever()方法來開始處理請求
- 關閉請求
server.handle_request() 只處理一個請求
server.forever() 處理多個請求,一直執行
四、事例
簡單的接收客戶端發送的信息,並將其轉換成大寫,再返回給客戶端
服務端:
# -*- coding: UTF-8 -*- import socketserver class MyTCPHandler(socketserver.BaseRequestHandler): """ The request handler class for our server. It is instantiated once per connection to the server, and must override the handle() method to implement communication to the client. """ def handle(self): while True: # 多次接收客戶端信息 # self.request is the TCP socket connected to the client self.data = self.request.recv(1024).strip() print("{} wrote:".format(self.client_address[0])) print(self.data) # just send back the same data, but upper-cased self.request.sendall(self.data.upper()) if __name__ == "__main__": HOST, PORT = "localhost", 9999 # Create the server, binding to localhost on port 9999 server = socketserver.TCPServer((HOST, PORT), MyTCPHandler) # Activate the server; this will keep running until you # interrupt the program with Ctrl-C server.serve_forever()
客戶端:
# -*- coding: UTF-8 -*- import socket client = socket.socket() client.connect(('localhost', 9999)) while True: msg = input('>>:').strip() if not msg: continue else: client.send(msg.encode('utf-8')) upData = client.recv(1024) print(upData.decode())
五、多線程處理
到目前為止我們所有的c/s連接都同時只能處理一個客戶端請求,多個客戶端請求時,要等前面的客戶端請求關閉后才能執行,包括上面的代碼也是。如果想讓socketserver並發起來, 必須選擇使用以下一個多並發的類:
class socketserver.ForkingTCPServer class socketserver.ForkingUDPServer class socketserver.ThreadingTCPServer class socketserver.ThreadingUDPServer
只需要改變一個地方就可以了
server = socketserver.TCPServer((HOST, PORT), MyTCPHandler)
服務端:
import socketserver class MyTCPHandler(socketserver.BaseRequestHandler): def handle(self): while True: # self.request is the TCP socket connected to the client self.data = self.request.recv(1024).strip() print("{} wrote:".format(self.client_address[0])) print(self.data) # just send back the same data, but upper-cased self.request.sendall(self.data.upper()) if __name__ == "__main__": HOST, PORT = "localhost", 9999 server = socketserver.ThreadingTCPServer((HOST, PORT), MyTCPHandler) server.serve_forever()