python網(wǎng)絡(luò)編程基礎(chǔ)(連載)03 socket-udp

2 socket模塊-UDP

gitbook鏈接:用python帶你進(jìn)入AI中的深度學(xué)習(xí)技術(shù)領(lǐng)域https://www.gitbook.com/book/scrappyzhang/python_to_deeplearn/details

github鏈接:https://github.com/ScrappyZhang/python_web_Crawler_DA_ML_DL

TCP/IP協(xié)議中的TCP和UDP協(xié)議都是通過一種名為套接字(socket)來實(shí)現(xiàn)網(wǎng)絡(luò)功能。套接字是一種類文件對(duì)象痢畜,它使得程序能夠接受客戶端的連接或者建立對(duì)客戶端的連接励稳,用以發(fā)送和接收數(shù)據(jù)。不論是客戶端程序還是服務(wù)器端程序散休,為了進(jìn)行網(wǎng)絡(luò)通信单鹿,都要?jiǎng)?chuàng)建套接字對(duì)象馏予。本章講解UDP協(xié)議用python套接字模塊的實(shí)現(xiàn)天梧。

2.1 UDP

2.1.1 udp定義

UDP 是User Datagram Protocol的簡(jiǎn)稱, 中文名是用戶數(shù)據(jù)報(bào)協(xié)議霞丧,是OSI(Open System Interconnection呢岗,開放式系統(tǒng)互聯(lián)) 參考模型中一種無連接的傳輸層協(xié)議,提供面向事務(wù)的簡(jiǎn)單不可靠信息傳送服務(wù)蛹尝,IETF RFC 768是UDP的正式規(guī)范后豫。UDP在IP報(bào)文的協(xié)議號(hào)是17。UDP有不提供數(shù)據(jù)包分組突那、組裝和不能對(duì)數(shù)據(jù)包進(jìn)行排序的缺點(diǎn)挫酿,也就是說,當(dāng)報(bào)文發(fā)送之后愕难,是無法得知其是否安全完整到達(dá)的早龟。UDP用來支持那些需要在計(jì)算機(jī)之間傳輸數(shù)據(jù)的網(wǎng)絡(luò)應(yīng)用。包括網(wǎng)絡(luò)視頻會(huì)議系統(tǒng)在內(nèi)的眾多的客戶/服務(wù)器模式的網(wǎng)絡(luò)應(yīng)用都需要使用UDP協(xié)議猫缭。

2.1.2 udp特性

(1) UDP是一個(gè)無連接協(xié)議葱弟,傳輸數(shù)據(jù)之前源端和終端不建立連接,當(dāng)它想傳送時(shí)就簡(jiǎn)單地去抓取來自應(yīng)用程序的數(shù)據(jù)饵骨,并盡可能快地把它扔到網(wǎng)絡(luò)上翘悉。在發(fā)送端,UDP傳送數(shù)據(jù)的速度僅僅是受應(yīng)用程序生成數(shù)據(jù)的速度居触、計(jì)算機(jī)的能力和傳輸帶寬的限制妖混;在接收端,UDP把每個(gè)消息段放在隊(duì)列中轮洋,應(yīng)用程序每次從隊(duì)列中讀一個(gè)消息段制市。 (2) 由于傳輸數(shù)據(jù)不建立連接,因此也就不需要維護(hù)連接狀態(tài)弊予,包括收發(fā)狀態(tài)等祥楣,因此一臺(tái)服務(wù)機(jī)可同時(shí)向多個(gè)客戶機(jī)傳輸相同的消息。 (3) UDP信息包的標(biāo)題很短汉柒,只有8個(gè)字節(jié)误褪,相對(duì)于TCP的20個(gè)字節(jié)信息包的額外開銷很小。 (4) 吞吐量不受擁擠控制算法的調(diào)節(jié)碾褂,只受應(yīng)用軟件生成數(shù)據(jù)的速率兽间、傳輸帶寬、源端和終端主機(jī)性能的限制正塌。 (5)UDP使用盡最大努力交付嘀略,即不保證可靠交付,因此主機(jī)不需要維持復(fù)雜的鏈接狀態(tài)表(這里面有許多參數(shù))乓诽。 (6)UDP是面向報(bào)文的帜羊。發(fā)送方的UDP對(duì)應(yīng)用程序交下來的報(bào)文,在添加首部后就向下交付給IP層鸠天。既不拆分讼育,也不合并,而是保留這些報(bào)文的邊界稠集,因此奶段,應(yīng)用程序需要選擇合適的報(bào)文大小。

雖然UDP是一個(gè)不可靠的協(xié)議巍杈,但它是分發(fā)信息的一個(gè)理想?yún)f(xié)議忧饭。例如,在屏幕上報(bào)告股票市場(chǎng)筷畦、在屏幕上顯示航空信息等等词裤。UDP也用在路由信息協(xié)議RIP(Routing Information Protocol)中修改路由表。在這些應(yīng)用場(chǎng)合下鳖宾,如果有一個(gè)消息丟失吼砂,在幾秒之后另一個(gè)新的消息就會(huì)替換它。UDP廣泛用在多媒體應(yīng)用中鼎文,例如渔肩,Progressive Networks公司開發(fā)的RealAudio軟件,它是在因特網(wǎng)上把預(yù)先錄制的或者現(xiàn)場(chǎng)音樂實(shí)時(shí)傳送給客戶機(jī)的一種軟件拇惋,該軟件使用的RealAudio audio-on-demand protocol協(xié)議就是運(yùn)行在UDP之上的協(xié)議周偎,大多數(shù)因特網(wǎng)電話軟件產(chǎn)品也都運(yùn)行在UDP之上抹剩。

2.2 socket模塊函數(shù)

python中實(shí)現(xiàn)套接字的基本模塊為socket。一般公共socket()函數(shù)來創(chuàng)建套接字蓉坎,并進(jìn)行網(wǎng)絡(luò)通信澳眷。要使用socket需要導(dǎo)入socket模塊:import socket。一般使用socket.socket()函數(shù)來創(chuàng)建套接字蛉艾。其語法如下:

socket.socket(family=AF_INET, type=SOCK_STREAM, proto)

其中: family為套接字家族名:AN_INET钳踊、AF_INET6、AF_UNIX勿侯、AF_CAN拓瞪、AF_RDS;AN_INET默認(rèn)值代表ipv4。 type為套接字類型:SOCK_STREAM助琐、SOCK_DGRAM祭埂、SOCK_RAW;SOCK_STREAM為TCP協(xié)議使用的類型,SOCK_DGRAM為UDP使用的類型弓柱。 proto為協(xié)議類型沟堡,默認(rèn)為0 。

常見的socket對(duì)象常用的方法有:

bind(address)

其參數(shù)address是由ip和端口組成的元組矢空,如('127.0.0.1', 8888) 航罗。如果ip地址為空,則表示本機(jī)屁药,它的作用為綁定端口粥血,使該程序在運(yùn)行時(shí)使用操作系統(tǒng)的固定指定端口。

listen(backlog)

其參數(shù)backlog是指在拒絕連接之前酿箭,操作系統(tǒng)允許此程序的最大掛起連接數(shù)量复亏。最小值為0.

accept()

等待進(jìn)入連接,并返回一個(gè)由新建的與客戶端的socket連接和客戶端地址組成的元組缭嫡,其中客戶的地址是由客戶端ip地址和端口組成的元組缔御。

close()

關(guān)閉套接字,停止連接妇蛀。

recv(buffersize[, flag])

TCP用于接收遠(yuǎn)程連接發(fā)來的信息耕突,并獲取該信息,python3中為bytes類型评架。buffersize為接收緩沖區(qū)的大小眷茁。阻塞函數(shù)

send(data[, flags])

TCP用于發(fā)送數(shù)據(jù),data為bytes類型纵诞,返回值為已經(jīng)發(fā)送的字節(jié)數(shù)上祈。

recvfrom(buffersize[, flag])

UDP用于接收遠(yuǎn)程連接發(fā)來的信息,并獲取該信息,python3中為bytes類型登刺。buffersize為接收緩沖區(qū)的大小籽腕。阻塞函數(shù)

sendto(data[, flags])

UDP用于發(fā)送數(shù)據(jù),data為bytes類型塘砸,返回值為已經(jīng)發(fā)送的字節(jié)數(shù)节仿。

2.3 UDP套接字流程

這幾章為了更好的無負(fù)擔(dān)學(xué)習(xí)套接字的客戶端和服務(wù)端程序?qū)W習(xí)晤锥,我們借助非常有名的網(wǎng)絡(luò)調(diào)試助手來充當(dāng)服務(wù)器或者客戶端進(jìn)行配合演示掉蔬。網(wǎng)絡(luò)調(diào)試助手的具體使用可以查看UDP操作https://jingyan.baidu.com/article/20b68a88a9c056796dec625e.html和TCP操作:https://jingyan.baidu.com/article/148a1921dc93e74d71c3b1d7.html。 本書采用mac的網(wǎng)絡(luò)調(diào)試助手演示矾瘾,其他系統(tǒng)的可以查看百度鏈接女轿。

udp01.png

udp02.png

根據(jù)UDP協(xié)議的無連接特點(diǎn),一般客戶端僅僅需要?jiǎng)?chuàng)建套接字壕翩、數(shù)據(jù)收發(fā)蛉迹、關(guān)閉套接字三個(gè)部分就可以完成了。服務(wù)器由于需要給眾多客戶端一個(gè)明確的連接地址和端口放妈,所以需要額外的綁定端口操作北救。下圖為UDP客戶端和UDP服務(wù)器之間的通信流程。

udp03.png

udp通信模型中芜抒,在通信開始之前珍策,不需要建立相關(guān)的鏈接,只需要發(fā)送數(shù)據(jù)即可宅倒,類似于生活中攘宙,"寫信"/“發(fā)短信“。


socket_udp_xinxiang.png

2.4 UDP客戶端實(shí)現(xiàn)

需求實(shí)現(xiàn):

向服務(wù)器發(fā)送一條數(shù)據(jù)拐迁,并接收來自服務(wù)器的數(shù)據(jù)蹭劈,并打印

根據(jù)流程圖書寫模塊代碼

導(dǎo)入套接字模塊

import socket

創(chuàng)建UDP套接字

sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

發(fā)數(shù)據(jù)

sock.sendto(data, address)

收數(shù)據(jù)

sock.recvfrom(buffersize)

關(guān)閉套接字

sock.close()

完整代碼

'''net01_udp_client.py'''

import socket  # 導(dǎo)入模塊

?

address = ('192.168.234.129', 8080)  # 服務(wù)器地址為192.168.234.129,端口號(hào)為8080

sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)  # 創(chuàng)建套接字

?

send_data = 'net01_udp_client.py'

print('要發(fā)送的數(shù)據(jù)為', send_data)

?

sock.sendto(send_data.encode('utf-8'), address)  # 發(fā)送數(shù)據(jù)為bytes類型

?

recv_data = sock.recvfrom(1024) # 接收到的數(shù)據(jù)為兩部分线召,recv_data[1]為數(shù)據(jù)發(fā)送端的地址铺韧,recv_data[2]為接收到的數(shù)據(jù)

print(recv_data[1], '傳送回來的數(shù)據(jù)為:', recv_data[0].decode('utf-8'))

?

sock.close()

實(shí)現(xiàn)結(jié)果


socket_udp_client.png

本節(jié)通過mac上運(yùn)行我們實(shí)例中的udp客戶端程序,在虛擬機(jī)上用linux上打開網(wǎng)絡(luò)助手作為UDP服務(wù)器缓淹。其中哈打,本地mac的ip為192.168.234.1,在運(yùn)行時(shí)系統(tǒng)自動(dòng)分配的端口號(hào)為58505;虛擬機(jī)上的linux系統(tǒng)的ip為192.168.234.129割卖,設(shè)定服務(wù)器端口號(hào)為8080前酿。 先讓服務(wù)端運(yùn)行(點(diǎn)擊連接網(wǎng)絡(luò)),然后運(yùn)行程序鹏溯,可以看到linux上的網(wǎng)絡(luò)調(diào)試助手接收到的數(shù)據(jù)為net01_udp_client.py罢维;然后通過設(shè)置網(wǎng)絡(luò)調(diào)試助手上的目標(biāo)ip和端口為我們的udp客戶端程序運(yùn)行的ip和端口(192.168.234.1, 58505),寫入數(shù)據(jù)(我已經(jīng)接收到數(shù)據(jù)了),點(diǎn)擊發(fā)送;在udp客戶端可以看到成功接收到了來自網(wǎng)絡(luò)調(diào)試助手發(fā)送的數(shù)據(jù)和相關(guān)地址信息肺孵。這樣我們就簡(jiǎn)單的實(shí)現(xiàn)了udp客戶端的收發(fā)功能和語法學(xué)習(xí)匀借。

2.5 UDP服務(wù)器端實(shí)現(xiàn)

需求實(shí)現(xiàn):

從客戶端收到一條數(shù)據(jù)后,在數(shù)據(jù)頭增加’來自服務(wù)器‘字符串平窘,然后一起轉(zhuǎn)發(fā)回客戶端吓肋,然后關(guān)閉服務(wù)器套接字。

根據(jù)流程圖書寫模塊代碼

導(dǎo)入套接字模塊

import socket

創(chuàng)建UDP套接字

sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

綁定端口

sock.bind(address)

收數(shù)據(jù)

sock.recvfrom(buffersize)

發(fā)數(shù)據(jù)

sock.sendto(data, address)

關(guān)閉套接字

sock.close()

完整代碼

'''net02_udp_server.py'''

import socket

?

sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

?

address = ('192.168.234.1', 8888)  # 地址:設(shè)定服務(wù)器要使用端口8888

sock.bind(address)  # 綁定端口

?

recv_data = sock.recvfrom(1024)  # 接收數(shù)據(jù)

send_data = '來自服務(wù)器' + recv_data[0].decode()  # 數(shù)據(jù)處理瑰艘,增加'來自服務(wù)器'

sock.sendto(send_data.encode('utf-8'), recv_data[1])  # 發(fā)送數(shù)據(jù)

?

sock.close()  # 關(guān)閉套接字

實(shí)現(xiàn)結(jié)果

本節(jié)通過mac上運(yùn)行我們實(shí)例中的udp服務(wù)端程序是鬼,在虛擬機(jī)上用linux上打開網(wǎng)絡(luò)助手作為UDP客戶端。其中紫新,本地mac的ip為192.168.234.1,設(shè)定綁定的端口號(hào)為8888均蜜;虛擬機(jī)上的linux系統(tǒng)的ip為192.168.234.129。 先運(yùn)行程序芒率,然后通過網(wǎng)絡(luò)調(diào)試助手指定發(fā)送ip和端口囤耳,發(fā)送數(shù)據(jù)’服務(wù)器你好‘,可以看到linux上的網(wǎng)絡(luò)調(diào)試助手接收到的數(shù)據(jù)為’來自服務(wù)器服務(wù)器你好‘偶芍。這樣我們就簡(jiǎn)單的實(shí)現(xiàn)了udp服務(wù)端的收發(fā)功能和語法學(xué)習(xí)充择。


socket_udp_server.png

如果把上一節(jié)的客戶端所要發(fā)送的目標(biāo)地址修改為本節(jié)所創(chuàng)建的服務(wù)器地址('192.168.234.1', 8888),我們會(huì)發(fā)現(xiàn)它們實(shí)現(xiàn)了通信:同一操作系統(tǒng)不同進(jìn)程間的通信匪蟀。

# address = ('192.168.234.129', 8080)  # 服務(wù)器地址為192.168.234.129椎麦,端口號(hào)為8080

address = ('192.168.234.1', 8888) # 和net02_udp_server服務(wù)器進(jìn)行通信
socket_udp_for_self.png

2.6 實(shí)例:UDP簡(jiǎn)易版聊天工具實(shí)現(xiàn)

需求實(shí)現(xiàn):

編寫1個(gè)程序,有2個(gè)功能:1.獲取鍵盤數(shù)據(jù)萄窜,并將其發(fā)送給指定方铃剔,2.接收數(shù)據(jù)并顯示。進(jìn)行簡(jiǎn)單選擇以上的2個(gè)功能調(diào)用實(shí)現(xiàn)相應(yīng)的功能查刻。

根據(jù)流程圖書寫模塊代碼

主程序 套接字創(chuàng)建與端口綁定
功能菜單:1键兜、發(fā)送數(shù)據(jù) 2、接收數(shù)據(jù)

功能調(diào)用:如果1穗泵,調(diào)用發(fā)送數(shù)據(jù)函數(shù)普气;如果2 調(diào)用接收數(shù)據(jù)函數(shù)

發(fā)送數(shù)據(jù)函數(shù) 輸入數(shù)據(jù)、指定方的ip和端口 發(fā)送數(shù)據(jù)

接收數(shù)據(jù)函數(shù) 接收數(shù)據(jù)并打印


socket_udp_chat_1.png

完整代碼

'''net03_udp_chat.py'''

import socket

?

?

def send_message():

   send_data = input('請(qǐng)輸入要發(fā)送的消息:\n')

   send_ip = input('請(qǐng)輸入要發(fā)送的ip:\n')

   send_port = input('請(qǐng)輸入要發(fā)送的端口:\n')

   send_address = (send_ip, int(send_port))

   sock.sendto(send_data.encode('utf-8'), send_address)

?

?

def recv_message():

   recv_data = sock.recvfrom(1024)  # 接收數(shù)據(jù)

   print('從', recv_data[1], '接收的數(shù)據(jù)為:', recv_data[0].decode('utf-8'))

?

?

if __name__ == '__main__':

   sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

?

   address = ('192.168.234.1', 8888)  # 地址:設(shè)定服務(wù)器要使用端口8888

   sock.bind(address)  # 綁定端口

?

   # 功能菜單顯示

   print('*' * 30)

   print('1佃延、發(fā)送數(shù)據(jù)')

   print('2现诀、接收數(shù)據(jù)')

   print('*' * 30)

   fun_num = input('請(qǐng)選擇并輸入指定數(shù)字:\n')  # 獲取鍵盤選項(xiàng)數(shù)據(jù)

?

   # 輸入判斷

   if fun_num == '1':

       send_message()

   elif fun_num == '2':

       recv_message()

   else:

       print('您輸入的數(shù)據(jù)有誤!程序結(jié)束')

實(shí)現(xiàn)結(jié)果


socket_udp_chat.png

本節(jié)運(yùn)行我們實(shí)例中的udp聊天器程序履肃,在虛擬機(jī)上用linux上打開網(wǎng)絡(luò)助手作為UDP客戶端仔沿。其中,我們的udp聊天器的ip為192.168.234.1,設(shè)定綁定的端口號(hào)為8888尺棋;虛擬機(jī)上的linux系統(tǒng)的ip為192.168.234.129封锉,設(shè)定服務(wù)器端口號(hào)為8080。 從下圖的結(jié)果可以看到,選擇不同的選項(xiàng)會(huì)進(jìn)入不同的模塊成福,來完成指定功能碾局。此時(shí)我們便完成了udp的基本學(xué)習(xí)。

2.7 小結(jié)

socket_udp_summary.png
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末奴艾,一起剝皮案震驚了整個(gè)濱河市净当,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌蕴潦,老刑警劉巖像啼,帶你破解...
    沈念sama閱讀 207,248評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異品擎,居然都是意外死亡埋合,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,681評(píng)論 2 381
  • 文/潘曉璐 我一進(jìn)店門萄传,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人蜜猾,你說我怎么就攤上這事秀菱。” “怎么了蹭睡?”我有些...
    開封第一講書人閱讀 153,443評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵衍菱,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我肩豁,道長(zhǎng)脊串,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,475評(píng)論 1 279
  • 正文 為了忘掉前任清钥,我火速辦了婚禮琼锋,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘祟昭。我一直安慰自己缕坎,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,458評(píng)論 5 374
  • 文/花漫 我一把揭開白布篡悟。 她就那樣靜靜地躺著谜叹,像睡著了一般。 火紅的嫁衣襯著肌膚如雪搬葬。 梳的紋絲不亂的頭發(fā)上荷腊,一...
    開封第一講書人閱讀 49,185評(píng)論 1 284
  • 那天,我揣著相機(jī)與錄音急凰,去河邊找鬼女仰。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的董栽。 我是一名探鬼主播码倦,決...
    沈念sama閱讀 38,451評(píng)論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼锭碳!你這毒婦竟也來了袁稽?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,112評(píng)論 0 261
  • 序言:老撾萬榮一對(duì)情侶失蹤擒抛,失蹤者是張志新(化名)和其女友劉穎推汽,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體歧沪,經(jīng)...
    沈念sama閱讀 43,609評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡歹撒,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,083評(píng)論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了诊胞。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片暖夭。...
    茶點(diǎn)故事閱讀 38,163評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖撵孤,靈堂內(nèi)的尸體忽然破棺而出迈着,到底是詐尸還是另有隱情,我是刑警寧澤邪码,帶...
    沈念sama閱讀 33,803評(píng)論 4 323
  • 正文 年R本政府宣布裕菠,位于F島的核電站,受9級(jí)特大地震影響闭专,放射性物質(zhì)發(fā)生泄漏奴潘。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,357評(píng)論 3 307
  • 文/蒙蒙 一影钉、第九天 我趴在偏房一處隱蔽的房頂上張望画髓。 院中可真熱鬧,春花似錦斧拍、人聲如沸雀扶。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,357評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽愚墓。三九已至,卻和暖如春昂勉,著一層夾襖步出監(jiān)牢的瞬間浪册,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,590評(píng)論 1 261
  • 我被黑心中介騙來泰國打工岗照, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留村象,地道東北人笆环。 一個(gè)月前我還...
    沈念sama閱讀 45,636評(píng)論 2 355
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像厚者,于是被迫代替她去往敵國和親躁劣。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,925評(píng)論 2 344

推薦閱讀更多精彩內(nèi)容