Python-网络编程之粘包、UDP
2024-08-27 20:48:22
粘包问题
什么是粘包问题呢?
在我们写 tcp socket编程的时候,tcp协议是一个流式的协议,服务端第一次发送的数据,客户端无法准确一次性的接收完毕,下一次发送的数据与上一次数据粘在一起。
即:
1、 无法预测对方需要接收的数据大小长度
2、 多次连续发送数据量小的,并且时间间隔短的数据 会一次性打包一起发送
TCP 协议的特性:
会将多次连续发送的数据量小的,并且时间间隔短的数据一次性发送完毕
subprocess模块
我们用subprocess 模块来演示一个粘包问题。
# 服务端
# coding=utf-8
import socket
import subprocess
server = socket.socket()
address = ("127.0.0.1",8888)
server.bind(address)
server.listen(5)
while True:
conn , addr = server.accept()
while True:
try:
cmd = conn.recv(1024).decode("utf-8")
print(cmd)
if cmd == "q":
break
obj = subprocess.Popen(
cmd,shell=True,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE
)
res = obj.stdout.read() + obj.stderr.read()
conn.send(res)
except Exception:
break
conn.close()
# 客户端
# coding=utf-8
import socket
client = socket.socket()
address = ("127.0.0.1",8888)
client.connect(address)
while True:
cmd = input("请输入>>>")
client.send(cmd.encode("utf-8"))
if cmd == "q":
break
data = client.recv(1024)
print(data.decode("gbk"))
client.close()
终端打印结果
请输入>>>tasklist
映像名称 PID 会话名 会话# 内存使用
========================= ======== ================ =========== ============
System Idle Process 0 Services 0 24 K
System 4 Services 0 3,172 K
smss.exe 352 Services 0 1,200 K
csrss.exe 464 Services 0 6,656 K
wininit.exe 572 Services 0 5,168 K
csrss.exe 588 Console 1 77,948 K
services.exe 636 Services 0 12,288 K
lsass.exe 652 Services 0 11,164 K
lsm.exe 660 Services 0 4,664 K
winlogon.exe 744 Console 1 8,180 K
svchost.exe 812 Services 0 10,040 K
svchost.
请输入>>>dir
exe 892 Services 0 8,280 K
svchost.exe 980 Services 0 21,744 K
svchost.exe 168 Services 0 21,060 K
svchost.exe 388 Services 0 40,792 K
svchost.exe 908 Services 0 12,252 K
WUDFHost.exe 1100 Services 0 8,096 K
ZhuDongFangYu.exe 1188 Services 0 23,784 K
svchost.exe 1236 Services 0 17,532 K
wlanext.exe 1412 Services 0 5,268 K
conhost.exe 1420 Services 0 2,860 K
dwm.exe 1536 Console 1 38,436 K
explorer.exe 1588 Console 1 70,028 K
spoolsv.exe 1612 Services 0 12,204 K
svchost.exe
我们看到在输完tasklist 命令之后,再次输入其他命令,还是上次命令的结果,
那么久证明了 服务端第一次发送的数据,客户端无法准确一次性的接收完毕,下一次发送的数据与上一次数据粘在一起。我们在客户端接收的时候,接收的数据大小是1024个字节,服务器执行结果 超出了接收的大小,所以相当于把结果堆到了后面,一起发送,所以下次执行命令得不到正确的结果,那么我们需要解决这个问题就需要用到 struct 模块
struct模块
struct 模块必须先定义报头,,先发送报头,再发送真实数据
# 服务端
# coding=utf-8
import struct
import socket
import subprocess
server = socket.socket()
address = ("127.0.0.1",8888)
server.bind(address)
server.listen(5)
while True:
conn,addr = server.accept()
while True:
try:
cmd = conn.recv(1024).decode("utf-8")
print(cmd)
if cmd == "q":
break
obj = subprocess.Popen(
cmd ,shell=True,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE
)
res = obj.stdout.read() + obj.stderr.read()
# 将执行结果计算长度用i模式打包
res_len = struct.pack("i",len(res))
# 先发送数据长度
conn.send(res_len)
# 再发送真实数据
conn.send(res)
except Exception:
break
conn.close()
# 客户端
# coding=utf-8
import socket
import struct
client = socket.socket()
address = ("127.0.0.1",8888)
client.connect(address)
while True:
cmd = input("请输入命令>>>")
client.send(cmd.encode("utf-8"))
if cmd == "q":
break
# 用struct模块接收的长度统一是4个字节,
head = client.recv(4)
# 然后用struct模块解包得到数据的真实长度,返回的是元组类型,0表示第一个元素,就是真实长度
data_len = struct.unpack("i",head)[0]
# 然后再把真实长度接收即可。
data = client.recv(data_len)
print(data.decode("gbk"))
client.close()
UDP协议编程
udp也是一种传输协议
1)不需要建立双向通道
2)不会粘包
3)客户端给服务端发送数据,不需要等待服务端返回接收成功
4)数据容易丢失,数据不安全。
TCP:就相当于与在打电话
UDP:就相当于与在发短信
简易qq聊天室
# 服务端
# coding=utf-8
import socket
server = socket.socket(type=socket.SOCK_DGRAM)
address = ("127.0.0.1",8888)
server.bind(address)
while True:
msg,addr = server.recvfrom(1024)
print(msg.decode("utf-8"))
# 服务端往客户端发送消息
send_msg = input("服务端发送消息")
server.sendto(send_msg.encode("utf-8"),addr)
# 客户端
# coding=utf-8
import socket
client = socket.socket(type=socket.SOCK_DGRAM)
address = ("127.0.0.1",8888)
while True:
send_msg = input("请输入信息")
client.sendto(send_msg.encode("utf-8"),address)
data = client.recv(1024)
print(data.decode("utf-8"))
最新文章
- MySQL 存储过程游标
- 也说说TIME_WAIT状态
- CRC
- JqGrid TreeView使用
- 八、mysql视图、存储过程、函数以及时间调度器
- ByteBuffer使用之道
- vmware vms migration to openstack
- js获取IP地址的方法小结
- java中spring提供的属性copy方法
- Luogu P1410 子序列
- 今天这篇内容分享Apache由http自动跳转到https的多种方法
- NodeJS Stream流
- 【转】spring boot mybatis 读取配置文件
- 总结5条对学习Linux系统有帮助的经验心得
- dos命令:批处理
- css 的 conic-gradient 学习
- dubbo监控报错Error creating bean with name 'uriBrokerService'
- SiteMap Editor for Microsoft Dynamics CRM 2011 使用说明
- Django框架基于session的登录/注销实现
- eclipse修改Properties资源文件的默认编码