粘包问题及解决

1>先模拟ssh,编写一个远程执行命令的程序

    其实也就是客户端输入命令,再由服务端执行并返回结果的一个过程,基于之前的简单通信脚本,改一下,如下


    当服务端收取命令之后,用subpcocess模块执行命令,并且把执行结果返回给客户端,客户端解码展示,客户端

    的代码及执行结果如下


2>粘包问题

    客户端更改接收字符串位数的上限,200,并且再传递一个新的命令,如‘查看C盘的文件’,但是注意返回结果,并不是当     前命令的结果,而是上一条命令的剩余部分!


理解TCP也称‘流式协议’,其实这个问题也很好理解,因服务端这边给客户端发送的数据肯定超过200字节,

而客户端这边这一次只收取200字节,所以,没取完的剩余部分依然存留在IO缓冲区(也可以理解为服务端

通往客户端的管道)里,等到客户端下一次来取值,所以,客户端再发送另外一个命令,服务端这边执行并把

新的结果再从管道传送给客户端,客户端取值就从上次的剩余部分开始了。

这就是-------粘包现象

粘包问题只存在于TCP,not UDP

3>粘包问题解析

    看一下客户端的‘粘包现象’,进行TCP协议通信时,,会启用

    一种优化方法(Nagle算法),将数据量小且发送间隔小的数据包合并成一个大的数据包发送,(这样可以节省网络IO

    ,减少延迟),所以如下所示,客户端发送了两次数据,但是服务端却一次就收完了,因为在发送时就合并了,所以服务端

    的第二次收取,没有任何数据。

    

    记住一点:客户端的发送与服务端的接收并不是一对一的关系,他们实质上都是把数据拷贝只各自的操作系统,

    至于操作系统怎么发,何时发,应用程序就根本管不到了。

4>解决粘包问题

    既然产生这个问题的原因就是----客户端设定的接收值小于实际值,其实也就是客户端并不知道服务端究竟会传多少数据

    过来(因为就是把接收的最大值写成无限大,也有超过的可能),所以,可以这样解决:发送端在发送数据前,把自己将

    要发送的字节流总大小让接收端知晓,然后接收端来一个死循环接收完所有数据。

    解决这个问题之前,先介绍一个内置的库,struck

    

    如上,不管原始数据大小(应该也有个范围),它的pack方法都能转换成一个4位长度的Bytes类型数据,然后再通过

    unpack解开,得到一个元祖类型的数据格式,第一个就是真实的值,所以,可以把个值加在真实数据的前面(头部),

    就当做数据的描述信息,告知对方我的数据大小,对方收到后,先取钱4个字节,解码得到数据大小,这样,知道了

    数据的大小,就知道如何收取数据了。

    步骤拆解,如下服务端的写法(注意下面的send,两次虽然分开写了,但是他们会组装到一起发送,nagle算法)


    客户端的写法


    这样写其实也可以。只是也有 total_size[0] 超出接收范围的情况。


5>更高级的解决粘包问题的方法

    上面的方法始终都有数据超出范围的风险,接下来设计一个字典类型的头部信息,让头部信息能包含更多数据,也更完美

    的解决 数据范围这个问题,

    因为始终还是在服务端返回数据问题,所以还是从服务端开始分析,优化,分解步骤

    思路:服务端步骤: 1>接收命令,2>执行命令,3>【注意注意:这里并不是发送结果也不是发送头大小】,而是先

    设计一个dic类型的头信息,里面至少应该包含真实文件的大小,再发送这个头信息的固定长度,4>发送头部信息,

    5>发送真实数据。

               客户端步骤:1>发送命令,2>接收头部信息大小,3>根据头部信息大小接收头部信息,4>根据头部信息中真实

     数据大小,接收真实数据。(这里的2,3,4步就是对应服务端的3,4,5)

    服务端代码如下


客户端


  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值