day8--socketserver
socketserver分類:
1、TCP協議
class socketserver.TCPServer(server_address,RequestHandlerClass,bind_and_activate=True)
2、UDP協議
class socketserver.UDPServer(server_address,RequestHandlerClass,bind_and_activate=True)
剩下兩種不常用協議如下:
calss socketserver.UnixStreamServer(server_address,RequestHandlerClass,bind_and_activate=True)
class socketserver.UnixDatagramServer(server_adddress,RequestHandlerClass,bind_and_activate=True)
協議之間的繼承關系如下:
用socketServer創建一個服務的步驟:
1、創建一個request handler class(請求處理類),合理選擇StreamRequestHandler和DatagramRequestHandler之中的一個作為父類(當然,便用BaseRequestHandler作為父類也可),并重寫它的handler()方法;
2、實例化一個server class對象,并將服務的地址和之前創建的request handler class傳遞給它;
3、調用server class對象的handle_request()或server_forver()方法來開始處理請求,server_forever()是永久處理連接,使用這一個。
handle_request()只處理一個請求,處理完一個請求之后退出;server_forever()處理多個請求。
??? 與客戶端每一個交互都是在handle()中處理的。
??? socketServer其實是對客戶端功能的進一步封裝,比如bind(),listen(),accept()功能的封裝,把這些功能統一分裝到socketserver中,并且能夠實現多線程,多進程的多并發的情況,客戶端沒有變化,下面來看一個簡單的例子:
??? socketserver寫成的服務器端:
'''使用socketserver創建客戶端''' import socketserverclass MyTCPHandler(socketserver.BaseRequestHandler):'''創建一個socketserver服務器接收端,首先實例化一個類'''def handle(self):self.data = self.request.recv(1024).strip() #接收客戶端發送的消息print("IP:%s,端口:%s鏈接進來了!!!" %(self.client_address[0],self.client_address[1]))'''打印那個客戶端端口連接過來了'''print(self.data.decode('utf-8')) #打印接收到的消息self.request.send(self.data.upper()) #把接收到的消息大寫返回回去if __name__ == "__main__":HOST,PORT = 'localhost',9999server = socketserver.TCPServer((HOST,PORT),MyTCPHandler)'''創建連接實例'''server.serve_forever()??? 上面代碼中,我們創建了socketserver實例的服務器端,其實原理與socket都是一樣的,不同的是,socketserver是對服務器端連接的封裝,如個別bind()、listen()、accept()的封裝,我們只需要self.request.recv(length).strip()接收數據即可,不用關心太多底層的問題,讓創建socket的過程變得簡單。
??? socket創建的客戶端:
'''創建一個socketserver客戶端,客戶端與socket客戶端是完全一樣的,只是服務器端不一樣而已''' import socketclient = socket.socket() client.connect(("localhost",9999)) while True:mess = input("請輸入您要發送的數據>>:")client.send(mess.encode('utf-8')) #客戶端發送數據給服務器端data = client.recv(1024) #客戶端接收服務器發送過來的數據print("接收到的數據:",data.decode('utf-8'))??? 上面代碼是socket創建的客戶端,就是一個簡單的收發數據,在這里能夠連續發送數據,下面來首先啟動服務器端,接著啟動客戶端進行交互。
運行如下:
請輸入您要發送的數據>>:dfasfdasd
接收到的數據: DFASFDASD
請輸入您要發送的數據>>:1
接收到的數據:
請輸入您要發送的數據>>:das
Traceback (most recent call last):
? File "/home/zhuzhu/第八天/socket_server/socketserver_client.py", line 8, in <module>
??? client.send(mess.encode('utf-8'))?? #客戶端發送數據給服務器端
BrokenPipeError: [Errno 32] Broken pipe
??? 從上面可以看出,第一次交互是沒有問題的,第二次交互就開始出錯了,為什么呢?我們來看下服務器端,在服務器端里面,handle()里面每次只能接收一次數據,因此會出現錯誤的情況,下面我們來讓服務器端實現連續交互,修改服務器端,如下:
??? 上面代碼中,對服務器進行了修改,讓服務器能夠循環接收數據,這樣客戶端就能無限發送和接收數據了,不過要牢記一點,客戶端是不能夠發送空的消息給服務器的,如果發送空的消息給服務器,就會卡主,傳遞不了消息,因而要設定發送空消息的指令。
??? 上面代碼修改了,能夠實現交互,但是我們發現了一個問題,服務器還是只能每次跟一個客戶端交互,不能同時跟多個客戶端交互,其他客戶端必須等待本次交互完成之后,在進行交互,這與socket寫的服務器和客戶端沒有區別,如何用socketserver實現多并發呢,下面有兩種方式,一種是多線程,如下:
??? (1)多線程
'''使用socketserver創建客戶端''' import socketserverclass MyTCPHandler(socketserver.BaseRequestHandler):'''創建一個socketserver服務器接收端,首先實例化一個類'''def handle(self):while True:self.data = self.request.recv(1024).strip() #接收客戶端發送的消息if not self.data:'''如果接收的為空,說明服務器端發送的是空的數據,或者是服務器端斷開了'''print(self.client_address,"客戶端斷開了!!!")breakprint("IP:%s,端口:%s鏈接進來了!!!" %(self.client_address[0],self.client_address[1]))'''打印那個客戶端端口連接過來了'''print(self.data.decode('utf-8')) #打印接收到的消息self.request.send(self.data.upper()) #把接收到的消息大寫返回回去if __name__ == "__main__":HOST,PORT = 'localhost',9997server = socketserver.ThreadingTCPServer((HOST,PORT),MyTCPHandler)'''創建連接實例'''server.serve_forever()??? 多線程就是修改server連接的方式,socketserver.ThreadingTCPServer即可,如下:
??? server = socketserver.ThreadingTCPServer((HOST,PORT),MyTCPHandler)
??? 上面修改之后,就能實現多線程多并發,我們可以同時啟動多個客戶端進行交互。
??? 上面啟動一個服務器,多個客戶端,交互如下:
客戶端1:請輸入您要發送的數據>>:這么神奇
接收到的數據: 這么神奇
客戶端2:
請輸入您要發送的數據>>:alex
接收到的數據: ALEX
客戶端3:
請輸入您要發送的數據>>:sb
接收到的數據: SB
客戶端4:
請輸入您要發送的數據>>:yes
接收到的數據: YES
服務器: IP:127.0.0.1,端口:54856鏈接進來了!!! 這么神奇 IP:127.0.0.1,端口:54858鏈接進來了!!! alex IP:127.0.0.1,端口:54860鏈接進來了!!! sb IP:127.0.0.1,端口:54862鏈接進來了!!! yes
??? 上面可以看出,我們實現了多線程多并發的交互,我們也可以實現多進程的交互。
??? (2)多進程
??? 多進程和多線程是一樣的,也是修改服務器端的交互指令即可,如下:
??? server = socketserver.ForkingTCPServer((HOST,PORT),MyTCPHandler)
??? 上面,ForKingTCPServer((IP,端口號),實例化的類),就實現了和多線程一個的多并發情況,如下:
'''使用socketserver創建客戶端''' import socketserverclass MyTCPHandler(socketserver.BaseRequestHandler):'''創建一個socketserver服務器接收端,首先實例化一個類'''def handle(self):while True:self.data = self.request.recv(1024).strip() #接收客戶端發送的消息if not self.data:'''如果接收的為空,說明服務器端發送的是空的數據,或者是服務器端斷開了'''print(self.client_address,"客戶端斷開了!!!")breakprint("IP:%s,端口:%s鏈接進來了!!!" %(self.client_address[0],self.client_address[1]))'''打印那個客戶端端口連接過來了'''print(self.data.decode('utf-8')) #打印接收到的消息self.request.send(self.data.upper()) #把接收到的消息大寫返回回去if __name__ == "__main__":HOST,PORT = 'localhost',9997server = socketserver.ForkingTCPServer((HOST,PORT),MyTCPHandler)'''創建連接實例'''server.serve_forever()??? 交互如下:
客戶端1: 請輸入您要發送的數據>>:dfasfdas 接收到的數據: DFASFDAS 客戶端2: 請輸入您要發送的數據>>:xiaozhuzhu 接收到的數據: XIAOZHUZHU 客戶端3: 請輸入您要發送的數據>>:pangshini 接收到的數據: PANGSHINI 客戶端4: 請輸入您要發送的數據>>:dapagnzhi 接收到的數據: DAPAGNZHI 服務器: IP:127.0.0.1,端口:54876鏈接進來了!!! dfasfdas IP:127.0.0.1,端口:54878鏈接進來了!!! xiaozhuzhu IP:127.0.0.1,端口:54880鏈接進來了!!! pangshini IP:127.0.0.1,端口:54886鏈接進來了!!! dapagnzhi??? 上面就是多進程下的多并發的交互情況,和多線程交互結果是一致的,不同的是,ForKingTCPServer()多進程在Windows下會報錯,由于Windows多進程和Linux多進程的原理是不一樣的。在Linux下沒有問題,在Windows下會報錯。
??? 基本的socketserver代碼:
?
import socketserverclass MyTCPHandler(socketserver.BaseRequestHandler):""" The request handler class for our server.It is instantiated once per connection to the server, and mustoverride the handle() method to implement communication to theclient.""" def handle(self):# self.request is the TCP socket connected to the clientself.data = self.request.recv(1024).strip()print("{} wrote:".format(self.client_address[0]))print(self.data)# just send back the same data, but upper-casedself.request.sendall(self.data.upper())if __name__ == "__main__":HOST, PORT = "localhost", 9999# Create the server, binding to localhost on port 9999server = socketserver.TCPServer((HOST, PORT), MyTCPHandler)# Activate the server; this will keep running until you# interrupt the program with Ctrl-Cserver.serve_forever()?
??? 總結:
??? (1)socketserver與socket是一樣的,都是為了實現客戶端和服務器端的交互;
??? (2)socketserver能夠實現多并發,而socket只能一對一的進行交互;
??? (3)socketserver.TCPServer是實現與socket一樣的一對一交互,socketserver.ThreadingTCPServer是實現多線程下的多并發,socketserver.ForkingTCPServer是實現多進程的下的多并發的數據交互,都是在TCP協議下進行交互的,常用的還有UDP協議。
??? (4)客戶端不能發送空的消息,服務器端也不能接收空的消息;
??? (5)如果服務器端接收的消息為空,說明客戶端已經退出了,不然若客戶端發送為空,則造成堵塞;
??? (6)socketserver是對socket中bind,listen,accept()的封裝。
轉載于:https://www.cnblogs.com/gengcx/p/7407256.html
總結
以上是生活随笔為你收集整理的day8--socketserver的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Nmap在pentest box中的扫描
- 下一篇: 链表专题