1.介紹
UDP --- 用戶數(shù)據(jù)報協(xié)議后控,是一個無連接的簡單的面向數(shù)據(jù)報的運輸層協(xié)議御雕。UDP不提供可靠性垛玻,它只是把應(yīng)用程序傳給IP層的數(shù)據(jù)報發(fā)送出去冤留,但是并不能保證它們能到達目的地。由于UDP在傳輸數(shù)據(jù)報前不用在客戶和服務(wù)器之間建立一個連接倡鲸,且沒有超時重發(fā)等機制供嚎,故而傳輸速度很快。
UDP是一種面向無連接的協(xié)議,每個數(shù)據(jù)報都是一個獨立的信息克滴,包括完整的源地址或目的地址逼争,它在網(wǎng)絡(luò)上以任何可能的路徑傳往目的地,因此能否到達目的地劝赔,到達目的地的時間以及內(nèi)容的正確性都是不能被保證的誓焦。
特點:UDP是面向無連接的通訊協(xié)議,UDP數(shù)據(jù)包括目的端口號和源端口號信息着帽,由于通訊不需要連接杂伟,所以可以實現(xiàn)廣播發(fā)送。 UDP傳輸數(shù)據(jù)時有大小限制仍翰,每個被傳輸?shù)臄?shù)據(jù)報必須限定在64KB之內(nèi)赫粥。 UDP是一個不可靠的協(xié)議,發(fā)送方所發(fā)送的數(shù)據(jù)報并不一定以相同的次序到達接收方予借。
UDP是面向消息的協(xié)議越平,通信時不需要建立連接,數(shù)據(jù)的傳輸自然是不可靠的灵迫,UDP一般用于多點通信和實時的數(shù)據(jù)業(yè)務(wù)秦叛,比如
- 語音廣播
- 視頻
- TFTP(簡單文件傳送)
- SNMP(簡單網(wǎng)絡(luò)管理協(xié)議)
- RIP(路由信息協(xié)議,如報告股票市場龟再,航空信息)
- DNS(域名解釋)
查看端口
- 用“netstat -an”查看端口狀態(tài)
2.udp網(wǎng)絡(luò)程序-發(fā)送數(shù)據(jù)
socket函數(shù)
mySocket = socket(family, type)
函數(shù)socket()的參數(shù)family用于設(shè)置網(wǎng)絡(luò)通信的域书闸,函數(shù)socket()根據(jù)這個參數(shù)選擇通信協(xié)議的族尼变。通信協(xié)議族在文件sys/socket.h中定義利凑。
函數(shù)socket()的參數(shù)type用于設(shè)置套接字通信的類型,主要有SOCKET_STREAM(流式套接字)嫌术、SOCK——DGRAM(數(shù)據(jù)包套接字)等哀澈。
并不是所有的協(xié)議族都實現(xiàn)了這些協(xié)議類型,例如度气,AF_INET協(xié)議族就沒有實現(xiàn)SOCK_SEQPACKET協(xié)議類型割按。
udp網(wǎng)絡(luò)程序-發(fā)送、接收數(shù)據(jù)
from socket import *
#1. 創(chuàng)建套接字
udpSocket = socket(AF_INET, SOCK_DGRAM)
#2. 準備接收方的地址
sendAddr = ('192.168.1.103', 8080)
#3. 從鍵盤獲取數(shù)據(jù)
sendData = input("請輸入要發(fā)送的數(shù)據(jù):")
#4. 發(fā)送數(shù)據(jù)到指定的電腦上
udpSocket.sendto(sendData, sendAddr)
#5. 等待接收對方發(fā)送的數(shù)據(jù)
recvData = udpSocket.recvfrom(1024) # 1024表示本次接收的最大字節(jié)數(shù)
#6. 顯示對方發(fā)送的數(shù)據(jù)
print(recvData)
#7. 關(guān)閉套接字
udpSocket.close()
echo服務(wù)器
from socket import *
# 1. 創(chuàng)建套接字
udpSocket = socket(AF_INET, SOCK_DGRAM)
# 2. 綁定本地的相關(guān)信息
bindAddr = ('', 7788) # ip地址和端口號磷籍,ip一般不用寫适荣,表示本機的任何一個ip
udpSocket.bind(bindAddr)
num = 1
while True:
# 3. 等待接收對方發(fā)送的數(shù)據(jù)
recvData = udpSocket.recvfrom(1024) # 1024表示本次接收的最大字節(jié)數(shù)
# 4. 將接收到的數(shù)據(jù)再發(fā)送給對方
#udpSocket.sendto(recvData[0], recvData[1])
udpSocket.sendto(str(len(recvData[0].decode('gbk'))).encode('gbk'), recvData[1])
# 5. 統(tǒng)計信息
print('已經(jīng)將接收到的第%d個數(shù)據(jù)返回給對方,內(nèi)容為:%s' % (num, recvData[0].decode('gbk')))
num += 1
# 5. 關(guān)閉套接字
udpSocket.close()
廣播
import socket
'''
1、一對一 點對點 單播
2院领、一對多 多播
3弛矛、一對所有 廣播
'''
#創(chuàng)建socket對象
udpSocket = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
#開啟廣播
udpSocket.setsockopt(socket.SOL_SOCKET,socket.SO_BROADCAST,1)
#目的地:如果是''表示當(dāng)前IP,如果是'<broadcast>'表示當(dāng)前所在的廣播地址
destAdress = ('<broadcast>',2425)
#消息內(nèi)容
sendMsg = input('>>')
#編碼
sendMsg = sendMsg.encode('gbk')
#發(fā)送
udpSocket.sendto(sendMsg,destAdress)
while True:
(content,address) = udpSocket.recvfrom(1024)
print("received from %s----%s" % (address, content.decode('gbk')))
#關(guān)閉socket對象
udpSocket.close()
print('over......')
要查看當(dāng)前廣播位置有3種方法
- 廣播的計算方法
- 在線網(wǎng)絡(luò)計算器
- 直接用<broadcast> 表示當(dāng)前所在的廣播地址
用代碼給飛秋發(fā)信息
'''
應(yīng)用程序可以在通用的tcp/ip協(xié)議基礎(chǔ)上比然,加上自己的判斷丈氓,組成新的應(yīng)用層協(xié)議。
比如飛秋,使用的是udp協(xié)議万俗,在此基礎(chǔ)上包裝成了IPMSG協(xié)議湾笛。
格式:
版本號:包編號:發(fā)送者姓名:發(fā)送者機器名:命令字:消息
1:12323434:user:machine:32:hello
1::13212321:易烊千璽:【易烊千璽】:32:努力來見我
注:現(xiàn)行的IPMSG協(xié)議的版本是1
'''
import socket
udpSocket = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
destAdress = ('192.168.11.66',2425)
sendMsg = input('>.')
sendMsg = sendMsg.encode('gbk')
udpSocket.sendto(sendMsg,destAdress)
udpSocket.close()
print('over..')
運行結(jié)果:
>.1::13212321:易烊千璽:【易烊千璽】:32:努力來見我
over..
收消息_沒綁定端口號
import socket
udpSocket=socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
destAdress=('192.168.11.66',8888)
sendMsg = input('--')
sendMsg = sendMsg.encode('gb2312')
udpSocket.sendto(sendMsg,destAdress)
recvMsg=udpSocket.recvfrom(1024)
recvMsg='【Receive from %s : %s 】: %s'%(recvMsg[1][0],recvMsg[1][1],recvMsg[0].decode('gbk'))
print(recvMsg)
udpSocket.close()
print('over.......')
收消息_綁定端口
import socket
#創(chuàng)建socket對象
udpSocket = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
'''
綁定,
第一個參數(shù)是本地ip,不指定也可以闰歪,默認會幫你填充,建議不寫
第二個參數(shù)是端口號嚎研,不要與本地的端口號沖突
'''
localAdress = ('',8081)
udpSocket.bind(localAdress)
#目的地
destAdress = ('192.168.11.66',8888)
#消息內(nèi)容
#sendMsg = input('>>')
#編碼
#sendMsg = sendMsg.encode('gb2312')
#發(fā)送
#udpSocket.sendto(sendMsg,destAdress)
'''
收,這個緩沖區(qū)不是越大越好,如果發(fā)送方的數(shù)據(jù)库倘,大于緩沖區(qū)嘉赎,丟包,報錯于樟。
如果收不到公条,阻塞
'''
recvMsg = udpSocket.recvfrom(1024)
recvMsg = '【Receive from %s : %s】:%s'%(recvMsg[1][0],recvMsg[1][1],recvMsg[0].decode('gbk'))
print(recvMsg)
#關(guān)閉socket對象
udpSocket.close()
print('over......')
多線程聊天
'''
收和發(fā)互相不影響:
這是兩個獨立的功能,可以考慮兩個線程
'''
from socket import *
from threading import *
import os
'''全局變量'''
# socket
udpSocket = None
# ip
destIp = None
# port
destPort = None
# 收
def recv():
while True:
recvInfo = udpSocket.recvfrom(1024)
print("\r<<%s:%s%s>>" % (str(recvInfo[1]), recvInfo[0].decode('gbk'),os.linesep),end='')
# 發(fā)
def send():
while True:
info = input('>>')
udpSocket.sendto(info.encode('gbk'), (destIp, destPort))
# 主方法
def main():
global udpSocket
global destIp
global destPort
udpSocket = socket(AF_INET, SOCK_DGRAM)
bindAddr = ('', 8888) # ip地址和端口號迂曲,ip一般不用寫靶橱,表示本機的任何一個ip
udpSocket.bind(bindAddr)
#destIp = input("對方的ip:")
#destPort = int(input("對方的port:"))
destIp = '192.168.11.66'
destPort = 8080
tSend = Thread(target=send)
tRecv = Thread(target=recv)
tSend.start()
tRecv.start()
if __name__ == '__main__':
main()
結(jié)果:
>>北方有佳人
<<('192.168.11.66', 8080):遺世而獨立
>>一顧傾人城
<<('192.168.11.66', 8080):再顧傾人國
>>
注釋
- os.linesep字符串給出當(dāng)前平臺使用的行終止符。例如路捧,Windows使用'\r\n'关霸,Linux使用'\n'而Mac使用'\r'。
- \r 默認表示將輸出的內(nèi)容返回到第一個指針杰扫,這樣的話队寇,后面的內(nèi)容會覆蓋前面的內(nèi)容