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收数据,数据丢失