粘包问题

什么是粘包问题呢?

在我们写 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"))

最新文章

  1. MySQL 存储过程游标
  2. 也说说TIME_WAIT状态
  3. CRC
  4. JqGrid TreeView使用
  5. 八、mysql视图、存储过程、函数以及时间调度器
  6. ByteBuffer使用之道
  7. vmware vms migration to openstack
  8. js获取IP地址的方法小结
  9. java中spring提供的属性copy方法
  10. Luogu P1410 子序列
  11. 今天这篇内容分享Apache由http自动跳转到https的多种方法
  12. NodeJS Stream流
  13. 【转】spring boot mybatis 读取配置文件
  14. 总结5条对学习Linux系统有帮助的经验心得
  15. dos命令:批处理
  16. css 的 conic-gradient 学习
  17. dubbo监控报错Error creating bean with name 'uriBrokerService'
  18. SiteMap Editor for Microsoft Dynamics CRM 2011 使用说明
  19. Django框架基于session的登录/注销实现
  20. eclipse修改Properties资源文件的默认编码

热门文章

  1. 如何提高阿里云cdn命中率?原命中率极低。
  2. JSON Web Token (JWT)生成Token及解密实战。
  3. Parallels Desktop Centos 设置IP
  4. Reverses CodeForces - 906E (最小回文分解)
  5. c++ socket 出现绑定失败的一个特殊原因。Bind failed Error:10049
  6. mysql分区partition详解
  7. JS去重算法
  8. 利用VS 性能探查器 解决代码性能不高问题
  9. thinkphp 切换数据库
  10. swoole手册