一、基於TCP協議
基於tcp的套接字,關鍵就是兩個循環,一個鏈接循環,一個通信循環
socketserver模塊中分兩大類:server類(解決鏈接問題)和request類(解決通信問題)
1.1 server類
1.2 request類
1.3 繼承關系
1.4 服務端
import socketserver
class MyHandler(socketserver.BaseRequestHandler):
def handle(self):
# 通信循環
while True:
# print(self.client_address)
# print(self.request) #self.request=conn
try:
data = self.request.recv(1024)
if len(data) == 0: break
self.request.send(data.upper())
except ConnectionResetError:
break
if __name__ == '__main__':
s = socketserver.ThreadingTCPServer(('127.0.0.1', 8080), MyHandler, bind_and_activate=True)
s.serve_forever() # 代表連接循環
# 循環建立連接,每建立一個連接就會啟動一個線程(服務員)+調用Myhanlder類產生一個對象,調用該對象下的handle方法,專門與剛剛建立好的連接做通信循環
1.5 客戶端
import socket
phone = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
phone.connect(('127.0.0.1', 8080)) # 指定服務端ip和端口
while True:
# msg=input('>>: ').strip() #msg=''
msg = 'client33333' # msg=''
if len(msg) == 0: continue
phone.send(msg.encode('utf-8'))
data = phone.recv(1024)
print(data)
phone.close()
1.6 客戶端1
import socket
phone = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
phone.connect(('127.0.0.1', 8080)) # 指定服務端ip和端口
while True:
# msg=input('>>: ').strip() #msg=''
msg = 'client11111' # msg=''
if len(msg) == 0: continue
phone.send(msg.encode('utf-8'))
data = phone.recv(1024)
print(data)
phone.close()
二、基於UDP協議
2.1 服務端
import socketserver
class MyHandler(socketserver.BaseRequestHandler):
def handle(self):
# 通信循環
print(self.client_address)
print(self.request)
data = self.request[0]
print('客戶消息', data)
self.request[1].sendto(data.upper(), self.client_address)
if __name__ == '__main__':
s = socketserver.ThreadingUDPServer(('127.0.0.1', 8080), MyHandler)
s.serve_forever()
2.2 客戶端
import socket
client = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) # 數據報協議-》udp
while True:
# msg=input('>>: ').strip() #msg=''
msg = 'client1111'
client.sendto(msg.encode('utf-8'), ('127.0.0.1', 8080))
data, server_addr = client.recvfrom(1024)
print(data)
client.close()
2.3 客戶端1
import socket
client = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) # 數據報協議-》udp
while True:
# msg=input('>>: ').strip() #msg=''
msg = 'client2222'
client.sendto(msg.encode('utf-8'), ('127.0.0.1', 8080))
data, server_addr = client.recvfrom(1024)
print(data)
client.close()
三、socketserver源碼分析
ftpserver=socketserver.ThreadingTCPServer(('127.0.0.1', 8080),FtpServer)
ftpserver.serve_forever()
-
查找屬性的順序:ThreadingTCPServer->ThreadingMixIn->TCPServer->BaseServer
-
實例化得到ftpserver,先找類ThreadingTCPServer的__init__,在TCPServer中找到,進而執行server_bind,server_active
-
找ftpserver下的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中找....
-
3.1 源碼總結
-
基於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即客戶端地址
- 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)>)