Python學習之UDP版socket&SocketServer


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即客戶端地址


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM