7.6 基於UDP的socket
無連接的,不必與對方建立連接,而是直接把數據發送給對方;
適用於一次傳輸銷量數據結構,可靠性不高的應用環境,因為其傳輸速率快
# 服務端
import socket
server = socket.socket(socket.AF_INET,socket.SOCK_DGRAM) #這里的餐宿已經改成UDP格式了
server.bind(('127.0.0.1',9000))
while 1:
from_client_data = server.recvfrom(1024)
print(f"來自{from_client_data[1]}的消息:{from_client_data[0].decode('utf-8')}")
se = input('>>>').encode('utf-8')
server.sendto(se,from_client_data[1])
# 客戶端
import socket
client = socket.socket(socket.AF_INET,socket.SOCK_DGRAM) #這里的餐宿已經改成UDP格式了
while 1:
se = input('>>>').encode('utf-8')
client.sendto(se,('127.0.0.1',9000))
re = client.recvfrom(1024)
print(f"來自{re[1]}的消息:{re[0].decode('utf-8')}")
# 雖然可以實現能夠與多個人進行數據交換,但實際上是在發送完數據后關閉了鏈接,並不是真正意義上的並行運行
7.7 socketserver實現並行運行
服務端
import socketserver
class Myserver(socketserver.BaseRequestHandler): # 定義的類名可以任意取,繼承的父類固定格式
def handle(self): # 必須要使用handle這個名字
print('listening_in_handle')
while 1:
from_client_data = self.request.recv(1024).decode('utf-8')
print(from_client_data)
to_client_data = input('>>>').strip()
self.request.send(to_client_data.encode('utf-8'))
if __name__ == '__main__':
ip_port = ('127.0.0.1',8006)
# socketserver.TCPServer.allow_reuse_address = True # 允許端口重復使用
server = socketserver.ThreadingTCPServer(ip_port,Myserver) # 固定格式
# 對 socketserver.ThreadingTCPServer 類實例化對象,將ip地址,端口號以及自己定義的類名傳入,並返回一個對象
server.serve_forever() # 固定格式,對象執行serve_forever方法,開啟服務端
print('listening_begin')
客戶端
可以設置多個客戶端
import socket
client = socket.socket()
client.connect(('127.0.0.1',8006))
while 1:
se = input('>>>').strip()
client.send(se.encode('utf-8'))
re = client.recv(1024).decode('utf-8')
print(f"the massage from server:{re}")
client.close()
分析
在整個socketserver這個模塊中,最主要的兩件事情:
1、一個是循環建立鏈接的部分,每個客戶端的鏈接都可以連接成功
2、一個通訊循環的部分,就是每個客戶端鏈接成功之后,要循環的和客戶端進行通信。
看代碼中的:server=socketserver.ThreadingTCPServer(('127.0.0.1',8006),MyServer)
通過print(socketserver.ThreadingTCPServer.mro())查看對象繼承的mro順序,找到它的繼承
查找屬性的順序: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__方法,其中:
tcp:
self.server即套接字對象
self.request即一個鏈接
self.client_address即客戶端地址
udp:
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即客戶端地址