爲何要講socketserver?咱們以前寫的tcp協議的socket是否是一次只能和一個客戶端通訊,若是用socketserver能夠實現和多個客戶端通訊。它是在socket的基礎上進行了一層封裝,也就是說底層仍是調用的socket,在py2.7裏面叫作SocketServer也就是大寫了兩個S,在py3裏面就小寫了。服務器
那麼咱們先看socketserver怎麼用呢,而後在分析,先看下面的代碼多線程
import socketserver #一、引入模塊 class MyServer(socketserver.BaseRequestHandler): #二、本身寫一個類,類名本身隨便定義,而後繼承socketserver這個模塊裏面的BaseRequestHandler這個類 def handle(self): #三、寫一個handle方法,必須叫這個名字 #self.request #六、self.request 至關於一個conn self.request.recv(1024) #七、收消息 msg = '親,學會了嗎' self.request.send(bytes(msg,encoding='utf-8')) #八、發消息 self.request.close() #九、關閉鏈接 # 拿到了咱們對每一個客戶端的管道,那麼咱們本身在這個方法裏面的就寫咱們接收消息發送消息的邏輯就能夠了 pass if __name__ == '__mian__': #thread 線程,如今只須要簡單理解線程,彆着急,後面很快就會講到啦,看下面的圖 server = socketserver.ThreadingTCPServer(('127.0.0.1',8090),MyServer)#四、使用socketserver的ThreadingTCPServer這個類,將IP和端口的元祖傳進去,還須要將上面我們本身定義的類傳進去,獲得一個對象,至關於咱們經過它進行了bind、listen server.serve_forever() #五、使用咱們上面這個類的對象來執行serve_forever()方法,他的做用就是說,個人服務一直開啓着,就像京東同樣,不能關閉網站,對吧,而且serve_forever()幫咱們進行了accept #注意: #有socketserver 那麼有socketclient的嗎? #固然不會有,我要做爲客戶去訪問京東的時候,京東幫我也客戶端了嗎,客戶端是否是在咱們本身的電腦啊,而且socketserver對客戶端沒有過高的要求,只須要本身寫一些socket就好了。
經過上面的代碼,咱們來分析socket的源碼:(你們還記得面向對象的繼承嗎,來,實戰的時候來啦)併發
在整個socketserver這個模塊中,其實就幹了兩件事情:一、一個是循環創建連接的部分,每一個客戶連接均可以鏈接成功 2、一個通信循環的部分,就是每一個客戶端連接成功以後,要循環的和客戶端進行通訊。 看代碼中的:server=socketserver.ThreadingTCPServer(('127.0.0.1',8090),MyServer) 還記得面向對象的繼承嗎?來,你們本身嘗試着看看源碼: 查找屬性的順序:ThreadingTCPServer->ThreadingMixIn->TCPServer->BaseServer 實例化獲得server,先找ThreadMinxIn中的__init__方法,發現沒有init方法,而後找類ThreadingTCPServer的__init__,在TCPServer中找到,在裏面建立了socket對象,進而執行server_bind(至關於bind),server_active(點進去看執行了listen) 找server下的serve_forever,在BaseServer中找到,進而執行self._handle_request_noblock(),該方法一樣是在BaseServer中 執行self._handle_request_noblock()進而執行request, client_address = self.get_request()(就是TCPServer中的self.socket.accept()),而後執行self.process_request(request, client_address) 在ThreadingMixIn中找到process_request,開啓多線程應對併發,進而執行process_request_thread,執行self.finish_request(request, client_address) 上述四部分完成了連接循環,本部分開始進入處理通信部分,在BaseServer中找到finish_request,觸發咱們本身定義的類的實例化,去找__init__方法,而咱們本身定義的類沒有該方法,則去它的父類也就是BaseRequestHandler中找.... 源碼分析總結: 基於tcp的socketserver咱們本身定義的類中的 self.server即套接字對象 self.request即一個連接 self.client_address即客戶端地址 基於udp的socketserver咱們本身定義的類中的 self.request是一個元組(第一個元素是客戶端發來的數據,第二部分是服務端的udp套接字對象),如(b'adsf', <socket.socket fd=200, family=AddressFamily.AF_INET, type=SocketKind.SOCK_DGRAM, proto=0, laddr=('127.0.0.1', 8080)>) self.client_address即客戶端地址
一個完整的sockeserver代碼示例:socket
import socketserver class Myserver(socketserver.BaseRequestHandler): def handle(self): self.data = self.request.recv(1024).strip() print("{} wrote:".format(self.client_address[0])) print(self.data) self.request.sendall(self.data.upper()) if __name__ == "__main__": HOST, PORT = "127.0.0.1", 9999 # 設置allow_reuse_address容許服務器重用地址 socketserver.TCPServer.allow_reuse_address = True # 建立一個server, 將服務地址綁定到127.0.0.1:9999 #server = socketserver.TCPServer((HOST, PORT),Myserver) server = socketserver.ThreadingTCPServer((HOST, PORT),Myserver) # 讓server永遠運行下去,除非強制中止程序 server.serve_forever()
客戶端代碼示例:tcp
import socket HOST, PORT = "127.0.0.1", 9999 data = "hello" # 建立一個socket連接,SOCK_STREAM表明使用TCP協議 with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock: sock.connect((HOST, PORT)) # 連接到客戶端 sock.sendall(bytes(data + "\n", "utf-8")) # 向服務端發送數據 received = str(sock.recv(1024), "utf-8")# 從服務端接收數據 print("Sent: {}".format(data)) print("Received: {}".format(received))