Python 網絡編程之 UDP 協議

UDP 和 TCP 的區別

  TCP UDP
鏈接性 面向鏈接 面向無鏈接
傳輸可靠性 可靠 不可靠
傳輸模式 數據報
應用場景 傳輸大量的數據 少許數據
速度

TCP:python

TCP 的可靠體如今傳輸數據以前,會有三次握手來創建鏈接。在數據傳完後,還會斷開鏈接用來節約系統資源。在數據傳遞時,有確認機制、重傳機制、擁塞控制機制以保證傳輸的可靠性,但這些機制都會消耗大量的時間和系統資源,每一個鏈接都會佔用系統的 CPU、內存等硬件資源,因此也致使 TCP 容易被人利用,好比 DDOS、CC 等攻擊。編程

通常用於文件傳輸、收發郵件或遠程登陸等對數據準確性要求高的場景。segmentfault

UDP:服務器

UDP 沒有 TCP 那些可靠的機制,因此在數據傳遞時,若是網絡質量很差,就會很容易丟包。但 UDP 也是沒法避免攻擊的,好比:UDP Flood 攻擊。網絡

通常用於即時通信、在線視頻、網絡電話等對傳輸效率要求高,但對準確性要求相對低的場景。socket

  • 面向有鏈接型

面向有鏈接型

發送數據以前,須要在收發主機之間創建一條通訊線路,在通訊傳輸先後,專門進行創建和斷開鏈接的處理,若是與對端之間沒法通訊,可避免發送無謂的數據。函數

  • 面向無鏈接型

面向無鏈接型

這種類型不要求創建和斷開鏈接,發送端可任什麼時候候發送數據,接收端也不知道本身什麼時候從哪裏接受數據,這種狀況下,接收端須要時常確認是否收到數據,彼此也不須要確認對方是否存在。編碼

關於 TCP 網絡編程的實現請參考個人另外一篇博文 Socket 通訊原理spa

UDP 網絡編程實現

面向無鏈接的 UDP 時序圖code

UDP 通訊過程

建立 Socket

sock = socket.socket(family=AF_INET, type=SOCK_STREAM, proto=0, fileno=None)
  1. family -> 地址族

    • socket.AF_UNIX: 用於同一臺機器上的進程通訊(既本機通訊)
    • socket.AF_INET: 用於服務器與服務器之間的網絡通訊
    • socket.AF_INET6: 基於 IPV6 方式的服務器與服務器之間的網絡通訊
  2. type -> Socket 對象的類型

    • socket.SOCK_STREAM: 基於 TCP 的流式 Socket 通訊
    • socket.SOCK_DGRAM: 基於 UDP 的數據報式 Socket 通訊
    • socket.SOCK_RAW: 原始套接字,普通的套接字沒法處理 ICMP、IGMP 等網絡報文,而 SOCK_RAW 能夠;其次 SOCK_RAW 也能夠處理特殊的 IPV4 報文;此外,利用原始套接字,能夠經過 IP_HDRINCL 套接字選項由用戶構造 IP 頭
    • socket.SOCK_SEQPACKET: 可靠的連續數據包服務
  3. proto -> 協議編號,默認是 0,通常能夠忽略該參數
  4. fileno -> Socket 的文件描述符,若是指定了 fileno,則其餘參數將被忽略,返回指定文件描述符的 Socket。
建立 TCP Socket:
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

建立 UDP Socket:
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

UDP 通訊

sock.recvfrom(bufsize[, flags])

接受 UDP 套接字的數據,與 recv() 相似,但返回值是 tuple(data, address)。其中 data 是包含接受數據的字符串,address 是發送數據的 Socket 地址

注意協議接收到的數據可能大於 buf 的長度,因此在這種狀況下要調用幾回 recv 函數才能把 Socket 接收緩衝區中的數據 copy 完。recv 函數僅僅是 copy 數據,真正接收數據是由協議來完成的。
sock.sendto(bytes, address)

發送 UDP 數據,將數據發送到 Socket,address 形式爲 tuple(ipaddr, port),指定遠程地址發送,返回值是發送的字節數

Python 2.x 發送的報文是 str 類型,Python 3.x 發送的報文是 bytes 類型,在發送前要記得編碼。

客戶端代碼

import socket

sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
address = ('127.0.0.1', 8020)

while True:
    msg = input('Wanna send: ')
    if not msg:
        break
    sock.sendto(bytes(msg, 'utf-8'), address)  # Return the number of bytes sent
    data, addr = sock.recvfrom(1024)
    data = data.decode('utf-8')
    print('Response:', data)

sock.close()

服務端代碼

import socket
import time

sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.bind(('127.0.0.1', 8020))

print('waiting for message...')
while True:
    data, addr = sock.recvfrom(1024)
    data = data.decode('utf-8')
    print('Got message from', addr)
    print('Received message:', data)
    sock.sendto(bytes('[%s] %s' % (time.ctime(), data), 'utf-8'), addr)

sock.close()
相關文章
相關標籤/搜索