首页 > 其他分享 >对解决粘包问题的理解

对解决粘包问题的理解

时间:2024-01-15 19:23:49浏览次数:24  
标签:name 粘包 header json 理解 file 解决 size socket

【一】什么是粘包问题

  • 想象你正在通过一条很窄的管道(网络连接)发送一串珠子(数据包)。在管道的另一端,有人(接收方)正在接收这些珠子。为了让对方知道每串珠子的开始和结束,你决定在每串珠子之间放一小块纸条(数据包的边界标记)。
  • 但是,如果这些珠子和纸条在管道中相互挤压,可能会导致纸条丢失或珠子串连在一起,使得接收方无法区分哪些珠子是一组。这就好比在网络传输过程中,原本独立的数据包因为紧密相连,而在接收端被误认为是一个连续的数据流,这就是所谓的“粘包”。
  • 在现实的网络通信中,由于TCP协议是基于流的,它只保证数据的顺序和完整性,而不保证数据包之间的界限。因此,如果发送方连续快速发送多个数据包,接收方可能会一次性接收到这些数据包的合并结果,而无法区分它们原来的界限。这就需要通过某些机制(如在每个数据包前添加长度信息)来明确标记数据包的界限,以避免粘包问题。

【二】TCP协议解决粘包问题思路

  • 将数据拆分出来一个头部,头部内容写了数据的大小,以及其他信息

  • 这里以一个传输视频的功能作为例子

  • 服务端

# 创建对象
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

# 绑定IP,端口
server.bind(('127.0.0.1', 8080))

# 创建半连接池
server.listen(5)

# 获取连接对象
obj, addr = server.accept()

# 接收文件名
file_name = obj.recv(1024).decode('utf8')

# 由一个字典装头部信息
header = {
    'file_name': file_name,  # 文件名称
    'file_size': os.path.getsize(file_name)  # 文件大小
}

# 用json把header变成json字符串格式
header_json = json.dumps(header)
# 转换成二进制
header_bytes = header_json.encode('utf-8')
# 计算头部长度
header_h = bytes(str(len(header_bytes)).encode('utf8')).zfill(2)

# 发送头部长度给客户端
obj.send(header_h)

# 发送头部数据给客户端
obj.send(header_bytes)
with open(file_name, 'rb') as fp:
    data = fp.read()
    obj.send(data)
obj.close()
server.close()

  • 客户端
import socket
import json

client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

client.connect(('127.0.0.1', 8080))

file_name = input('请输入文件名:>>>>').strip()
client.send(file_name.encode('utf8'))
new_file_name = f'new_{file_name}'
header_size = int(client.recv(2).decode('utf8'))
header_json = client.recv(header_size).decode('utf8')
header = json.loads(header_json)
file_size = header.get('file_size')
res_size = 0
with open(new_file_name, 'wb') as fp:
    while res_size < file_size:
        data = client.recv(1024)
        fp.write(data)
        res_size += len(data)

client.close()
  • 服务端将文件的信息如文件名,文件大小存放在字典里作为头部信息
  • 并且把头部的长度也发送给客户端
  • 客户端收到头部的长度后,再继续以头部的长度精准接收到头部信息,也就是服务端发送的第二个内容
  • 然后客户端再起一个变量来记录收到数据的大小,直到收到数据的大小等于头部信息里面的文件大小,才会断开连接
  • 这样就解决了粘包问题

标签:name,粘包,header,json,理解,file,解决,size,socket
From: https://www.cnblogs.com/Hqqqq/p/17966106

相关文章

  • 前端跨域三种解决方式(CORS、JSONP、代理跨域)
    什么是跨域?跨域是浏览器为了安全而作出的限制策略(所以服务端不涉及到跨域);浏览器请求必须遵循同源策略,即同域名、同端口、同协议;例如:http://www.abc.com到http://www.def.com的请求会出现跨域(域名不同)http://www.abc.com:3000到http://www.abc.com:3001的请求会出现跨域(端口不同......
  • 设备树 memory reg 的理解。
    再设备树中经常见到这样的描述。   这里adress使用两个u32来描述,length使用两个u32来描述。 实际上address=0x0000000040000000length=0x0c0000000 是拼起来的。至于是不是加上0x,感觉可加可不加。......
  • electron安装卡住问题解决
    问题安装electron会卡住,你换镜像,挂梯子都没有用。解决办法自己配置下载electron二进制文件的地址解决步骤npmconfigls进入该配置文件,手动添加ELECTRON_MIRROR=https://npmmirror.com/mirrors/electron/electron_mirror=npm.taobao.org这两行重新npminstallele......
  • 解决Github port443:Timed out
    Failedtoconnecttogithub.comport443:Timedout修改Git的网络设置注意修改成自己的代理的IP和端口号gitconfig--globalhttp.proxyhttp://127.0.0.1:7890gitconfig--globalhttps.proxyhttp://127.0.0.1:7890取消代理是因为,访问Gitee或其它是不需要梯子,所......
  • nuxt3: 使用 NuxtImg 不生效和请求报500的解决办法
    前言NuxtImg默认使用了IPX作为图形修改器,IPX是NuxtImage的内置和自托管图像优化器。但是我在使用时却报了500的错误,下面分享一下解决问题的过程正文安装配置依赖#安装依赖yarnadd@nuxt/image//nuxt.config.tsexportdefaultdefineNuxtConfig({modules:['@......
  • Spring解决泛型擦除的思路不错,现在它是我的了。
    你好呀,我是歪歪。Spring的事件监听机制,不知道你有没有用过,实际开发过程中用来进行代码解耦简直不要太爽。但是我最近碰到了一个涉及到泛型的场景,常规套路下,在这个场景中使用该机制看起来会很傻,但是最终了解到Spring有一个优雅的解决方案,然后去了解了一下,感觉有点意思。和你......
  • 对计算机系统的理解
    ​ 该图是我对系统的大致了解,从下往上,随着抽象程度的增加,由硬件走向软件。其中硬件系统包括输入输出设备,存储器,控制器和运算器。运算器和控制器统称为中央处理器,当然随着GPU计算和人工智能的兴起,GPU也越来越多的参与到运算器中。存储器包括硬盘和内存,输入输出设备便是我们常用的......
  • 消息队列常见问题及解决方案
    一、如何保证MQ的高可用性——(消息丢失)RabbitMQ镜像模式镜像集群模式是所谓的RabbitMQ的高可用模式,跟普通集群模式不一样的是,你创建的queue,无论元数据还是queue里的消息都会存在于多个实例上,然后每次你写消息到queue的时候,都会自动把消息到多个实例的queue里进行消息......
  • element-forge在Linux Centos中打包构建时遇到的异常问题解决方案
    环境:LinuxCentOS8x64electron:27.1.0electron-forge:7.1.0electrondev依赖包"devDependencies":{"@electron-forge/cli":"^7.1.0","@electron-forge/maker-deb":"^7.1.0","@electron-forge/maker-rpm&quo......
  • IDEA解决每次拉去项目都要重新配置Maven
    电脑要去配置Maven的话自己去搜一个,网上一堆一堆的每次重新打开一个项目,或者拉去一个项目都要重新去配置maven,好烦啊.现在我们配置一遍,就不用总是去配置了第一:关闭现在的项目第二: 第三配置自己的maven地址就行了......