標籤:get init nis utf-8 span _for 開始 mil 進程
python 基礎之socket編程(三)
前面實現的基於socket通訊只能實現什麼呢?在tcp協議的通訊中就是一個使用者說一句,服務端給你回一句,你再給服務端說一句,服務端再給你回一句,就這樣一直友好的玩耍下去了。等等,又有一個使用者來了,他呢也想和和服務端進行一下交流,於是他就給服務端發送了一條訊息,之後等呀等不知過了多久,任然沒有等到服務端給他發揮的訊息,只有什麼時候他就可以和服務端愉快的玩耍了呢?這個就需要第一個使用者退出和伺服器的連結,此時第二個用戶端才會和服務端建立起連結,此時此刻,他才能和服務端愉快的玩耍。當然有人會說,tcp不求行,那可以用udp 搞嘛,這個可以做,不過呢,資料丟失了我找你要呀。so,今天使用Python提供的一個模組來實現並發的效果,這個模組是啥呢?沒錯就是socketserver.
基於tcp的通訊端,實質就是兩個迴圈,一個迴圈實現串連;一個迴圈實現通訊。
socketserver模組中分兩大類:server類(解決連結問題)和request類(解決通訊問題)。
socketserver內部使用 IO多工 以及 “多線程” 和 “多進程” ,從而實現並發處理多個用戶端請求的Socket服務端。即:每個用戶端請求串連到伺服器時,Socket服務端都會在伺服器是建立一個“線程”或者“進程” 專門負責處理當前用戶端的所有請求。底層還是對socket進行了封裝和加入線程、進程就實現了socketserver,後面會對socketserver源碼分析。
以下述代碼為例,分析socketserver源碼:
1 f=socketserver.ThreadingTCPServer((‘127.0.0.1‘,8080),MyServer)2 f.serve_forever()
尋找屬性的順序:ThreadingTCPServer->ThreadingMixIn->TCPServer->BaseServer:
- 執行個體化得到f,先找類ThreadingTCPServer的__init__,在TCPServer中找到,進而執行server_bind,server_active
- 找f下的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即用戶端地址
基於tcp的socketserver執行個體:
import socketserverclass Myserver(socketserver.BaseRequestHandler): def handle(self): print(‘self:‘, self) print(‘self.request:‘, self.request) while True: data = self.request.recv(1024) print(data) self.request.send(data.upper()) #將用戶端發來的單詞全部大寫後回複給用戶端if __name__ == ‘__main__‘: f = socketserver.ThreadingTCPServer((‘127.0.0.1‘, 8080), Myserver) f.serve_forever()
服務端
import socketclient = socket.socket(socket.AF_INET, socket.SOCK_STREAM)client.connect((‘127.0.0.1‘, 8080))while True: #通訊迴圈 msg = input(‘>>>: ‘).strip() if not msg: continue client.send(msg.encode(‘utf-8‘)) data = client.recv(1024) print(data)client.close()
用戶端1,2
so,今天就這些了,接下來得去搞定搞定多使用者FTP小項目啦。
Python 基礎之socket編程(三)