Python中的端口協議之基於UDP協議的通信傳輸


UDP協議:

  1、python中基於udp協議的客戶端與服務端通信簡單過程實現

  2、udp協議的一些特點(與tcp協議的比較)

       3、利用socketserver模塊實現udp傳輸協議的並發通信

-------------------------------------------------------------------------------------------------------------------------------------

一、UDP協議:OSI七層協議中的傳輸協議的一種(另外一種tcp協議),他們都是一種端口協議

  • 與TCP協議不同的是,UDP協議在傳輸時候無需雙方建立雙向連接,只需要知道對方的IP和PORT(端口)就可以

  而且UDP協議傳輸具有不安全行,或者說是即時性,給對方發送信息時候,只管發,至於他收不收得到都不會去考慮,

  不管是服務端還是客戶端都一樣。

  • UDP叫數據報協議,意味着發消息都帶有數據報頭,UDP的server不需要進行監聽也無需建立連接,在啟動服務之后只能被動的等待客戶端發消息過來,客戶端發消息的時候,要帶上服務端的地址,服務端在回消息的時候,也要帶上客戶端的地址

  下面來簡單實現基於UDP協議的客戶端、服務端通信

#  服務端:

import socket
# udp傳輸的服務端無需半連接池,因為通信無需建立雙向連接通道,無需三次握手四次揮手,只要知道對方ip和port就行
server = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
server.bind(('127.0.0.1', 8080))

# 通信循環
while True:
    data, client_addr = server.recvfrom(1024)  # 這里接收用recvfrom
    print('收到客戶端發來的udp消息%s' % data.decode('utf-8'))
    server.sendto(data.upper(), client_addr)  # 這里發送用sendto

#  客戶端:

import socket
#  無需connect服務端,因為發送時候跟上服務端ip和port就行
client = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

while True:
    msg = 'hello'
    client.sendto(msg.encode('utf-8'), ('127.0.0.1', 8080))
    data, server_addr = client.recvfrom(1024)
    print(data.decode('utf-8'))

二、UDP協議的一些特點

總結幾個UDP協議的特點:

  • 客戶端允許發空
  • 不會粘包
  • 服務端不存在的時候,客戶端照發無誤,不會報錯(*-*)
  • 可以實現簡單的並發效果
    # 驗證UDP是否有粘包問題:
    from socket import *
    server = socket(AF_INET, SOCK_DGRAM)
    server.bind(('127.0.0.1', 8080))
    
    while True:
        data1, addr = server.recvfrom(1024)
        data2, addr = server.recvfrom(1024)
        data3, addr = server.recvfrom(1024)
        data4, addr = server.recvfrom(1024)
        data5, addr = server.recvfrom(1024)
    
        print(data1)
        print(data2)
        print(data3)
        print(data4)
        print(data5)
    
    from socket import *
    client = socket(AF_INET, SOCK_DGRAM)
    
    while True:
        client.sendto(b'Hello1', ('127.0.0.1', 8080))
        client.sendto(b'Hello2', ('127.0.0.1', 8080))
        client.sendto(b'Hello3', ('127.0.0.1', 8080))
        client.sendto(b'Hello4', ('127.0.0.1', 8080))
        client.sendto(b'Hello5', ('127.0.0.1', 8080))
    
    # 打印的每條數據都是獨立的,沒有2條數據在一起的情況
    UDP不存在粘包問題,是由於UDP發送的時候,沒有經過Nagle算法的優化,不會將多個小包合並一次發送出去。另外,在UDP協議的接收端,采用了鏈式結構來記錄每一個到達的UDP包,這樣接收端應用程序一次recv只能從socket接收緩沖區中讀出一個數據包。也就是說,發送端send了幾次,接收端必須recv幾次(無論recv時指定了多大的緩沖區)。

三、利用socketserver模塊實現udp協議的並發通信

## 服務端:
import socketserver
from threading import currentThread  # 這里導入當前線程方法,得到當前線程名稱


class MyUdpHandler(socketserver.BaseRequestHandler):
    def handle(self):
        # 這里和tcp利用socketserver模塊並發的服務端不一樣,tcp服務端是直接data = self.request.recv(1024)
        data, sock = self.request  # 這里多了一個sock,這個sock用於發送,同時self對象本身可以得到client_address  
        msg = '%s [%s]' % (currentThread().name, data.upper().decode('utf-8'))
        sock.sendto(msg.encode('utf-8'), self.client_address)


if __name__ == '__main__':
    server = socketserver.ThreadingUDPServer(('127.0.0.1', 8080), MyUdpHandler)
    server.serve_forever()

##  客戶端
from threading import Thread,currentThread
import time
from socket import *
def task():
    client = socket(AF_INET,SOCK_DGRAM)
    addr = ('127.0.0.1', 8080)
    n = 0
    while n < 10:   # 模擬讓每個客戶端與服務端通信循環10次。
        msg = '%s [%s]' % (currentThread().name, n)
        client.sendto(msg.encode('utf-8'), addr)
        data, addr0 = client.recvfrom(1024)
        print(data.decode('utf-8'))
        n += 1

if __name__ == '__main__':
    for i in range(50):    # 開啟50個客戶端線程去連接服務端,模擬並發
        t = Thread(target=task)
        t.start()

 


免責聲明!

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



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