与TCP相同的是 客户端也不需要bind一个固定端口 让系统随机分一个
UDP和TCP异同处
UDP在使用时
1.修改socket的参数 第一个任然是AF_INET 第二个需要换成AOCK_DGRAM
2.UDP 不需要建立连接 所以没有三次握手和四次挥手
相同点:
服务器:都需要绑定端口和ip
recv与recvfrom都是阻塞的
不同点:
服务器:不需要监听和接受请求
TCP服务器默认只能与一个客户端进行通讯 下一个客户端必须等待上一个断开连接才能被处理
UDP多个客户端的请求会被一次处理 由于不需要建立连接 所以给你感觉时好像可以同时处理
客户端:不需要建立连接 直接发送即可
可以发送空消息
在UDP中 无论是客户端还是服务器 接受:recvfrom 发送:sendto
UDP是基于数据报的协议
发送和接收都是以数据报为单位
而TCP得单位是字节
接收方的缓冲区大小即使大于发送方发送的数据长度 也不会沾包
当接受方缓冲区的长度小于数据报的长度 windows会报异常 而Linux不会 缓冲区有多大就收几个
注意:UDP在使用时,必须保证收到的缓冲区大小 大于或等于发送的数据
由于缓冲区大小不可能无限大 所以UDP不适用于数据量较大的情况下 如果一定要使用UDP来传输大量数据的话
需要自己来对数据进行切割和组装
udp最大的数据报 受数据帧大小限制 最大为1472字节
TCP发送数据后 不会立即删除缓存数据 需要等到对方确认信息到达
结论:当数据量较大时 需要TCP
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
import socket c=socket.socket(socket.AF_INET,socket.SOCK_DGRAM) addr=('127.0.0.1',8808) c.sendto('hello 我是udp客户端'.encode(),addr) print('over') data,addr=c.recvfrom(1024) print(data.decode(),addr)
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
import socket s=socket.socket(socket.AF_INET,socket.SOCK_DGRAM) s.bind(('127.0.0.1',8808)) while True: data,addr=s.recvfrom(1024) s.sendto(data.upper(),addr) print(data)
自定义报头
发送端:
1.先将所有的额外信息打包到一个头中
2.然后先发送头部数据
3.最后发送真实数据
接收端:
1.接收固定长度的头部长度数据
2.根据长度数据获取头部数据
3.根据头部数据获取真实数据
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
import struct def send_msg(data,c): # 发数据 data = data.encode("utf-8") len_bytes = struct.pack("q",len(data)) c.send(len_bytes) c.send(data) def recv_msg(sock): # 接收响应 length = struct.unpack("q",sock.recv(8))[0] # 已接收长度 c_size = 0 # 存储总数据 data = b"" while c_size < length: res = sock.recv(1024) if not res: break c_size += len(res) data += res # 拼接数据 # 长度符合则接收成功 if length == c_size: print("接收成功") return data.decode("utf-8")
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
import socket import tool s = socket.socket(socket.AF_INET,socket.SOCK_STREAM) s.bind(("127.0.0.1",8989)) # 0 - 1023 > 可用端口 < 65535 s.listen() # 最大的半连接数量限制 while True: c,addr = s.accept() while True: try: # 从操作系统缓冲区读取1024到应用程序 data = tool.recv_msg(c) # 阻塞函数 等到操作系统缓冲区有数据为止 if not data: # 对方正常下线 ,,linux对方异常断开连接 c.close() break print(data) # 返回数据 tool.send_msg(data.upper(),c) except Exception as e: # 抛出异常仅在windows下 对方异常下线才会发生 print(e) c.close() break
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
import socket import tool c = socket.socket() c.connect(("127.0.0.1",8989)) # 就在执行三次握 while True: msg = input(">>>:") if not msg: continue tool.send_msg(msg,c) # 发送 res = tool.recv_msg(c) # 接收 print(res)