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 收数据, 数据丢失
来源: http://www.bubuko.com/infodetail-2676401.html