UDP通信過程
udp 不需要經過3次握手和4次揮手,不需要提前建立連接,直接發數據就行。
server端
import socket
BUFSIZE = 1024
ip_port = ('127.0.0.1', 9999)
server = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) # udp協議
server.bind(ip_port)
while True:
data,client_addr = server.recvfrom(BUFSIZE)
print('server收到的數據', data)
server.sendto(data.upper(),client_addr)
server.close()
client端
import socket
BUFSIZE = 1024
client = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
while True:
msg = input(">> ").strip()
ip_port = ('127.0.0.1', 9999)
client.sendto(msg.encode('utf-8'),ip_port)
data,server_addr = client.recvfrom(BUFSIZE)
print('客戶端recvfrom ',data,server_addr)
client.close()
輸出結果
server:
server收到的數據 b'hello'
server收到的數據 b'world'
client:
>> hello
客戶端recvfrom b'HELLO' ('127.0.0.1', 9999)
>> world
客戶端recvfrom b'WORLD' ('127.0.0.1', 9999)
>>
粘包分析
第一種:
server
from socket import *
import time
server=socket(AF_INET,SOCK_DGRAM)
server.bind(('127.0.0.1',8880))
res1=server.recvfrom(10) #b'hello'
print('第一次:',res1)
res2=server.recvfrom(1024) #b'world'
print('第二次:',res2)
server.close()
client
from socket import *
import time
client = socket(AF_INET, SOCK_DGRAM)
client.sendto(b'hello',('127.0.0.1',8880))
client.sendto(b'world',('127.0.0.1',8880))
client.close()
服務端結果:沒有產生粘包
第一次: (b'hello', ('127.0.0.1', 63959)) 第二次: (b'world', ('127.0.0.1', 63959))
第二種:
server:
from socket import *
import time
server=socket(AF_INET,SOCK_DGRAM)
server.bind(('127.0.0.1',8880))
res1=server.recvfrom(2) #b'he'
print('第一次:',res1)
time.sleep(6)
res2=server.recvfrom(1024) #b'world'
print('第二次:',res2)
server.close()
client:
from socket import *
import time
client = socket(AF_INET, SOCK_DGRAM)
client.sendto(b'hello',('127.0.0.1',8880))
time.sleep(5)
client.sendto(b'world',('127.0.0.1',8880))
client.close()
輸出結果
windows直接報錯:
Traceback (most recent call last):
/路飛/第三模塊/第二章網絡編程/06 基於udp協議的套接字/服務端.py", line 24, in <module>
res1=server.recvfrom(2) #b'he'
OSError: [WinError 10040] 一個在數據報套接字上發送的消息大於內部消息緩沖區或其他一些網絡限制,或該用戶用於接收數據報的緩沖區比數據報小。
mac或linux:
直接丟包,只收到b'he',后面的llo不會收到
TCP VS UDP
tcp基於鏈接通信
- 基於鏈接,則需要listen(backlog),指定連接池的大小
- 基於鏈接,必須先運行的服務端,然后客戶端發起鏈接請求
- 對於mac系統:如果一端斷開了鏈接,那另外一端的鏈接也跟着完蛋recv將不會阻塞,收到的是空(解決方法是:服務端在收消息后加上if判斷,空消息就break掉通信循環)
- 對於windows/linux系統:如果一端斷開了鏈接,那另外一端的鏈接也跟着完蛋recv將不會阻塞,收到的是空(解決方法是:服務端通信循環內加異常處理,捕捉到異常后就break掉通訊循環)
udp無鏈接
- 無鏈接,因而無需listen(backlog),更加沒有什么連接池之說了
- 無鏈接,udp的sendinto不用管是否有一個正在運行的服務端,可以己端一個勁的發消息,只不過數據丟失
- recvfrom收的數據小於sendinto發送的數據時,在mac和linux系統上數據直接丟失,在windows系統上發送的比接收的大直接報錯
- 只有sendinto發送數據沒有recvfrom收數據,數據丟失
