類型
-
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:\python37\lib\socketserver.py", line 313, in _handle_request_noblock
self.process_request(request, client_address)
File "D:\python37\lib\socketserver.py", line 344, in process_request
self.finish_request(request, client_address)
File "D:\python37\lib\socketserver.py", line 357, in finish_request
self.RequestHandlerClass(request, client_address, self)
File "D:\python37\lib\socketserver.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
這部分就是多線程的主要代碼