基於UDP的socket
面向無連接的不可靠數據傳輸,可以沒有服務器端,只不過沒有服務器端,發送的數據會被直接丟棄,並不能到達服務器端
由於UDP是面向無連接的(實際上有鏈接,不然通過什么去傳數據去取數據),可以使用多個客戶端連接服務端,但這並不是並發訪問。
注意:
1. 發消息,都是將數據發送到己端的發送緩沖中,收消息都是從己端的緩沖區中收
tcp:send發消息,recv收消息
udp:sendto發消息,recvfrom收消息
2. tcp是基於數據流的,而udp是基於數據報的:
send(bytes_data):發送數據流,數據流bytes_data若為空,自己這段的緩沖區也為空,操作系統不會控制tcp協議發空包
sendinto(bytes_data,ip_port):發送數據報,bytes_data為空,還有ip_port,所有即便是發送空的bytes_data,數據報其實也不是空的,自己這端的緩沖區收到內容,操作系統就會控制udp協議發包。
3.1 tcp協議
(1)如果收消息緩沖區里的數據為空,那么recv就會阻塞(阻塞很簡單,就是一直在等着收)
(2)只不過tcp協議的客戶端send一個空數據就是真的空數據,客戶端即使有無窮個send空,也跟沒有一個樣。
(3)tcp基於鏈接通信
- 基於鏈接,則需要listen(backlog),指定半連接池的大小
- 基於鏈接,必須先運行的服務端,然后客戶端發起鏈接請求
- 對於mac系統:如果一端斷開了鏈接,那另外一端的鏈接也跟着完蛋recv將不會阻塞,收到的是空(解決方法是:服務端在收消息后加上if判斷,空消息就break掉通信循環)
- 對於windows/linux系統:如果一端斷開了鏈接,那另外一端的鏈接也跟着完蛋recv將不會阻塞,收到的是空(解決方法是:服務端通信循環內加異常處理,捕捉到異常后就break掉通訊循環)
3.2 udp協議
(1)如果如果收消息緩沖區里的數據為“空”,recvfrom也會阻塞
(2)只不過udp協議的客戶端sendinto一個空數據並不是真的空數據(包含:空數據+地址信息,得到的報仍然不會為空),所以客戶端只要有一個sendinto(不管是否發送空數據,都不是真的空數據),服務端就可以recvfrom到數據。
(3)udp無鏈接
- 無鏈接,因而無需listen(backlog),更加沒有什么連接池之說了
- 無鏈接,udp的sendinto不用管是否有一個正在運行的服務端,可以己端一個勁的發消息,只不過數據丟失
- recvfrom收的數據小於sendinto發送的數據時,在mac和linux系統上數據直接丟失,在windows系統上發送的比接收的大直接報錯
- 只有sendinto發送數據沒有recvfrom收數據,數據丟失
實現代碼
服務端:
#導入socket模塊
import socket
#創建socket
skt = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
#綁定地址和端口
skt.bind(('127.0.0.1',9090))
#循環
while True:
#調用接受消息
data,addr = skt.recvfrom(1024)
#接受成功回復消息
rst = b'I am fine'
skt.sendto(rst,addr)
print('server Done')
#關閉鏈接
skt.close()
客戶端
#導入模塊
import socket
#創建socket
skt = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
#創建發送消息和發送目標
msg = b'Hello world'
addr = ('127.0.0.1',9090)
skt.sendto(msg,addr)
#接受回復
rst = skt.recvfrom(1024)
print(rst)
print('client done')
#關閉鏈接
skt.close()
