溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

Python腳本如何演示UDP器與客戶端

發(fā)布時(shí)間:2021-12-04 10:38:41 來源:億速云 閱讀:151 作者:柒染 欄目:網(wǎng)絡(luò)安全

今天就跟大家聊聊有關(guān)Python腳本如何演示UDP器與客戶端,可能很多人都不太了解,為了讓大家更加了解,小編給大家總結(jié)了以下內(nèi)容,希望大家根據(jù)這篇文章可以有所收獲。

小編先介紹傳輸層的另一個(gè)核心協(xié)議 UDP,再比較 TCP 與 UDP 的特點(diǎn),最后借助 Python 腳本演示 UDP 服務(wù)器與客戶端的通信過程。

0x01 UDP 協(xié)議

UDP(User Datagram Protocol,用戶數(shù)據(jù)報(bào)協(xié)議)是一種無連接、不可靠、基于數(shù)據(jù)報(bào)的傳輸層通信協(xié)議。

  • UDP 的通信過程與 TCP 相比較為簡(jiǎn)單,不需要復(fù)雜的三次握手與四次揮手,體現(xiàn)了無連接;

  • UDP 傳輸速度比 TCP 快,但容易丟包、數(shù)據(jù)到達(dá)順序無保證、缺乏擁塞控制、秉承盡最大努力交付的原則,體現(xiàn)了不可靠;

  • UDP 的無連接與不可靠特性注定無法采用字節(jié)流的通信模式,由協(xié)議名中的「Datagram」與 socket 類型中的「SOCK_DGRAM」即可體現(xiàn)它基于數(shù)據(jù)報(bào)的通信模式。

為了更直觀地比較 TCP 與 UDP 的異同,筆者將其整理成以下表格:


TCPUDP
連接模式面向連接(單點(diǎn)通信)無連接(多點(diǎn)通信)
傳輸可靠性可靠不可靠
通信模式基于字節(jié)流基于數(shù)據(jù)報(bào)
報(bào)頭結(jié)構(gòu)復(fù)雜(至少20字節(jié))簡(jiǎn)單(8字節(jié))
傳輸速度
資源需求
到達(dá)順序保證不保證
流量控制
擁塞控制
應(yīng)用場(chǎng)合大量數(shù)據(jù)傳輸少量數(shù)據(jù)傳輸
支持的應(yīng)用層協(xié)議Telnet、FTP、SMTP、HTTPDNS、DHCP、TFTP、SNMP

0x02 Network Socket

Network Socket(網(wǎng)絡(luò)套接字)是計(jì)算機(jī)網(wǎng)絡(luò)中進(jìn)程間通信的數(shù)據(jù)流端點(diǎn),廣義上也代表操作系統(tǒng)提供的一種進(jìn)程間通信機(jī)制。

進(jìn)程間通信(Inter-Process Communication,IPC)的根本前提是能夠唯一標(biāo)示每個(gè)進(jìn)程。在本地主機(jī)的進(jìn)程間通信中,可以用 PID(進(jìn)程 ID)唯一標(biāo)示每個(gè)進(jìn)程,但 PID 只在本地唯一,在網(wǎng)絡(luò)中不同主機(jī)的 PID 則可能發(fā)生沖突,因此采用「IP 地址 + 傳輸層協(xié)議 + 端口號(hào)」的方式唯一標(biāo)示網(wǎng)絡(luò)中的一個(gè)進(jìn)程。

小貼士:網(wǎng)絡(luò)層的 IP 地址可以唯一標(biāo)示主機(jī),傳輸層的 TCP/UDP 協(xié)議和端口號(hào)可以唯一標(biāo)示該主機(jī)的一個(gè)進(jìn)程。注意,同一主機(jī)中 TCP 協(xié)議與 UDP 協(xié)議的可以使用相同的端口號(hào)。

所有支持網(wǎng)絡(luò)通信的編程語言都各自提供了一套 socket API,下面以 Python 3 為例,講解服務(wù)器與客戶端建立 UDP 通信連接的交互過程:

Python腳本如何演示UDP器與客戶端

可見,UDP 的通信過程比 TCP 簡(jiǎn)單許多,服務(wù)器少了監(jiān)聽與接受連接的過程,而客戶端也少了請(qǐng)求連接的過程。客戶端只需要知道服務(wù)器的地址,直接向其發(fā)送數(shù)據(jù)即可,而服務(wù)器也敞開大門,接收任何發(fā)往自家地址的數(shù)據(jù)。

小貼士:由于 UDP 采用無連接模式,可知 UDP 服務(wù)器在接收到客戶端發(fā)來的數(shù)據(jù)之前,是不知道客戶端的地址的,因此必須是客戶端先發(fā)送數(shù)據(jù),服務(wù)器后響應(yīng)數(shù)據(jù)。而 TCP 則不同,TCP 服務(wù)器接受了客戶端的連接后,既可以先向客戶端發(fā)送數(shù)據(jù),也可以等待客戶端發(fā)送數(shù)據(jù)后再響應(yīng)。

0x03 UDP 服務(wù)器

#!/usr/bin/env python3# -*- coding: utf-8 -*-import socket

s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.bind(("127.0.0.1", 6000))
print("UDP bound on port 6000...")while True:
    data, addr = s.recvfrom(1024)
    print("Receive from %s:%s" % addr)
    if data == b"exit":
        s.sendto(b"Good bye!\n", addr)
        continue    s.sendto(b"Hello %s!\n" % data, addr)
  • Line 5:創(chuàng)建 socket 對(duì)象,第一個(gè)參數(shù)為 socket.AF_INET,代表采用 IPv4 協(xié)議用于網(wǎng)絡(luò)通信,第二個(gè)參數(shù)為 socket.SOCK_DGRAM,代表采用 UDP 協(xié)議用于無連接的網(wǎng)絡(luò)通信。

  • Line 6:向 socket 對(duì)象綁定服務(wù)器主機(jī)地址 ("127.0.0.1", 6000),即本地主機(jī)的 UDP 6000 端口。

  • Line 9:進(jìn)入與客戶端交互數(shù)據(jù)的循環(huán)階段。

  • Line 10:接收客戶端發(fā)來的數(shù)據(jù),包括 bytes 對(duì)象 data,以及客戶端的 IP 地址和端口號(hào) addr,其中 addr 為二元組 (host, port)。

  • Line 11:打印接收信息,表示從地址為 addr 的客戶端接收到數(shù)據(jù)。

  • Line 12:若 bytes 對(duì)象為 b"exit",則向地址為 addr 的客戶端發(fā)送結(jié)束響應(yīng)信息 b"Good bye!\n"。發(fā)送完畢后,繼續(xù)等待其他 UDP 客戶端發(fā)來數(shù)據(jù)。

  • Line 15:若 bytes 對(duì)象不為 b"exit",則向地址為 addr 的客戶端發(fā)送問候響應(yīng)信息 b"Hello %s!\n",其中 %s是客戶端發(fā)來的 bytes 對(duì)象。發(fā)送完畢后,繼續(xù)等待任意 UDP 客戶端發(fā)來數(shù)據(jù)。

與 TCP 服務(wù)器相比,UDP 服務(wù)器不必使用多線程,因?yàn)樗鼰o需為每個(gè)通信過程創(chuàng)建獨(dú)立連接,而是采用「即收即發(fā)」的模式,又一次體現(xiàn)了 UDP 的無連接特性。

0x04 UDP 客戶端

#!/usr/bin/env python3# -*- coding: utf-8 -*-import socket

s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
addr = ("127.0.0.1", 6000)while True:
    data = input("Please input your name: ")
    if not data:
        continue    s.sendto(data.encode(), addr)
    response, addr = s.recvfrom(1024)
    print(response.decode())
    if data == "exit":
        print("Session is over from the server %s:%s\n" % addr)
        breaks.close()
  • Line 5:創(chuàng)建 socket 對(duì)象,第一個(gè)參數(shù)為 socket.AF_INET,代表采用 IPv4 協(xié)議用于網(wǎng)絡(luò)通信,第二個(gè)參數(shù)為 socket.SOCK_DGRAM,代表采用 UDP 協(xié)議用于無連接的網(wǎng)絡(luò)通信。

  • Line 6:初始化 UDP 服務(wù)器的地址 ("127.0.0.1", 6000),即本地主機(jī)的 UDP 6000 端口。

  • Line 8:進(jìn)入與服務(wù)器交互數(shù)據(jù)的循環(huán)階段。

  • Line 9:要求用戶輸入名字。

  • Line 10:當(dāng)用戶的輸入為空時(shí),則重新開始循環(huán),要求用戶重新輸入。

  • Line 12:當(dāng)用戶的輸入非空時(shí),則將字符串轉(zhuǎn)換為 bytes 對(duì)象后,發(fā)送至地址為 ("127.0.0.1", 6000) 的 UDP 服務(wù)器。

  • Line 13:接收服務(wù)器的響應(yīng)數(shù)據(jù),包括 bytes 對(duì)象 response,以及服務(wù)器的 IP 地址和端口號(hào) addr,其中 addr 為二元組 (host, port)。

  • Line 14:將響應(yīng)的 bytes 對(duì)象 response 轉(zhuǎn)換為字符串后打印輸出。

  • Line 15:當(dāng)用戶的輸入為 "exit" 時(shí),則打印會(huì)話結(jié)束信息,終止與服務(wù)器交互數(shù)據(jù)的循環(huán)階段,即將關(guān)閉套接字。

  • Line 19:關(guān)閉套接字,不再向服務(wù)器發(fā)送數(shù)據(jù)。

0x05 UDP 進(jìn)程間通信

將 UDP 服務(wù)器與客戶端的腳本分別命名為 udp_server.py 與 udp_client.py,然后存至桌面,筆者將在 Windows 10 系統(tǒng)下用 PowerShell 進(jìn)行演示。

小貼士:讀者進(jìn)行復(fù)現(xiàn)時(shí),要確保本機(jī)已安裝 Python 3,注意筆者已將默認(rèn)的啟動(dòng)路徑名 python 改為了 python3。

單服務(wù)器 VS 多客戶端

Python腳本如何演示UDP器與客戶端

  1. 在其中一個(gè) PowerShell 中運(yùn)行命令 python3 ./udp_server.py,服務(wù)器綁定本地主機(jī)的 UDP 6000 端口,并打印信息 UDP bound on port 6000...,等待客戶端發(fā)來數(shù)據(jù);

  2. 在另兩個(gè) PowerShell 中分別運(yùn)行命令 python3 ./udp_client.py,并向服務(wù)器發(fā)送字符串 Client1Client2;

  3. 服務(wù)器打印接收信息,表示分別從 UDP 63643、63644端口接收到數(shù)據(jù),并分別向客戶端發(fā)送問候響應(yīng)信息;

  4. 客戶端 Client1 發(fā)送空字符串,則被要求重新輸入;

  5. 客戶端 Client2 先發(fā)送字符串 Alice,得到服務(wù)器的問候響應(yīng)信息,再發(fā)送字符串 exit,得到服務(wù)器的結(jié)束響應(yīng)信息,最后打印會(huì)話結(jié)束信息,終止與服務(wù)器的數(shù)據(jù)交互;

  6. 客戶端 Client1 發(fā)送字符串 exit,得到服務(wù)器的結(jié)束響應(yīng)信息,并打印會(huì)話結(jié)束信息,終止與服務(wù)器的數(shù)據(jù)交互;

  7. 服務(wù)器按照以上客戶端的數(shù)據(jù)發(fā)送順序打印接收信息,并繼續(xù)等待任意 UDP 客戶端發(fā)來數(shù)據(jù)。

0x06 Python API Reference

socket 模塊

本節(jié)介紹上述代碼中用到的內(nèi)建模塊 socket,是 Python 網(wǎng)絡(luò)編程的核心模塊。

socket() 函數(shù)

socket() 函數(shù)用于創(chuàng)建網(wǎng)絡(luò)通信中的套接字對(duì)象。函數(shù)原型如下:

socket.socket(family=AF_INET, type=SOCK_STREAM, proto=0, fileno=None)
  • family 參數(shù)代表地址族(Address Family),默認(rèn)值為 AF_INET,用于 IPv4 網(wǎng)絡(luò)通信,常用的還有 AF_INET6,用于 IPv6 網(wǎng)絡(luò)通信。family 參數(shù)的可選值取決于本機(jī)操作系統(tǒng)。

  • type 參數(shù)代表套接字的類型,默認(rèn)值為 SOCK_STREAM,用于 TCP 協(xié)議(面向連接)的網(wǎng)絡(luò)通信,常用的還有 SOCK_DGRAM,用于 UDP 協(xié)議(無連接)的網(wǎng)絡(luò)通信。

  • proto 參數(shù)代表套接字的協(xié)議,默認(rèn)值為 0,一般忽略該參數(shù),除非 family 參數(shù)為 AF_CAN,則 proto 參數(shù)需設(shè)置為 CAN_RAW 或 CAN_BCM。

  • fileno 參數(shù)代表套接字的文件描述符,默認(rèn)值為 None,若設(shè)置了該參數(shù),則其他三個(gè)參數(shù)將會(huì)被忽略。

創(chuàng)建完套接字對(duì)象后,需使用對(duì)象的內(nèi)置函數(shù)完成網(wǎng)絡(luò)通信過程。注意,以下函數(shù)原型中的「socket」是指 socket 對(duì)象,而不是上述的 socket 模塊。

bind() 函數(shù)

bind() 函數(shù)用于向套接字對(duì)象綁定 IP 地址與端口號(hào)。注意,套接字對(duì)象必須未被綁定,并且端口號(hào)未被占用,否則會(huì)報(bào)錯(cuò)。函數(shù)原型如下:

socket.bind(address)
  • address 參數(shù)代表套接字要綁定的地址,其格式取決于套接字的 family 參數(shù)。若 family 參數(shù)為 AF_INET,則 address 參數(shù)表示為二元組 (host, port),其中 host 是用字符串表示的主機(jī)地址,port 是用整型表示的端口號(hào)。

sendto() 函數(shù)

sendto() 函數(shù)用于向遠(yuǎn)程套接字對(duì)象發(fā)送數(shù)據(jù)。注意,該函數(shù)用于 UDP 進(jìn)程間的無連接通信,遠(yuǎn)程套接字的地址在參數(shù)中指定,因此使用前不需要先與遠(yuǎn)程套接字連接。相對(duì)地,TCP 進(jìn)程間面向連接的通信過程需要用 send() 函數(shù)。函數(shù)原型如下:

socket.sendto(bytes[, flags], address)
  • bytes 參數(shù)代表即將發(fā)送的 bytes 對(duì)象數(shù)據(jù)。例如,對(duì)于字符串 "hello world!" 而言,需要用 encode() 函數(shù)轉(zhuǎn)換為 bytes 對(duì)象 b"hello world!" 才能進(jìn)行網(wǎng)絡(luò)傳輸。

  • flags 可選參數(shù)用于設(shè)置 sendto() 函數(shù)的特殊功能,默認(rèn)值為 0,也可由一個(gè)或多個(gè)預(yù)定義值組成,用位或操作符 | 隔開。詳情可參考 Unix 函數(shù)手冊(cè)中的 sendto(2),flags 參數(shù)的常見取值有 MSG_OOB、MSG_EOR、MSG_DONTROUTE 等。

  • address 參數(shù)代表遠(yuǎn)程套接字的地址,其格式取決于套接字的 family 參數(shù)。若 family 參數(shù)為 AF_INET,則 address 參數(shù)表示為二元組 (host, port),其中 host 是用字符串表示的主機(jī)地址,port 是用整型表示的端口號(hào)。

sendto() 函數(shù)的返回值是發(fā)送數(shù)據(jù)的字節(jié)數(shù)。

recvfrom() 函數(shù)

recvfrom() 函數(shù)用于從遠(yuǎn)程套接字對(duì)象接收數(shù)據(jù)。注意,與 sendto() 函數(shù)不同,recvfrom() 函數(shù)既可用于 UDP 進(jìn)程間通信,也能用于 TCP 進(jìn)程間通信。函數(shù)原型如下:

socket.recvfrom(bufsize[, flags])
  • bufsize 參數(shù)代表套接字可接收數(shù)據(jù)的最大字節(jié)數(shù)。注意,為了使硬件設(shè)備與網(wǎng)絡(luò)傳輸更好地匹配,bufsize 參數(shù)的值最好設(shè)置為 2 的冪次方,例如 4096。

  • flags 可選參數(shù)用于設(shè)置 recv() 函數(shù)的特殊功能,默認(rèn)值為 0,也可由一個(gè)或多個(gè)預(yù)定義值組成,用位或操作符 |隔開。詳情可參考 Unix 函數(shù)手冊(cè)中的 recvfrom(2),flags 參數(shù)的常見取值有 MSG_OOB、MSG_PEEK、MSG_WAITALL 等。

recvfrom() 函數(shù)的返回值是二元組 (bytes, address),其中 bytes 是接收到的 bytes 對(duì)象數(shù)據(jù),address 是發(fā)送方的 IP 地址與端口號(hào),用二元組 (host, port) 表示。注意,recv() 函數(shù)的返回值只有 bytes 對(duì)象數(shù)據(jù)。

close() 函數(shù)

close() 函數(shù)用于關(guān)閉本地套接字對(duì)象,釋放與該套接字連接的所有資源。

socket.close()

看完上述內(nèi)容,你們對(duì)Python腳本如何演示UDP器與客戶端有進(jìn)一步的了解嗎?如果還想了解更多知識(shí)或者相關(guān)內(nèi)容,請(qǐng)關(guān)注億速云行業(yè)資訊頻道,感謝大家的支持。

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI