粘包问题及解决

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

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

粘包问题及解决_第1张图片

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

    的代码及执行结果如下

粘包问题及解决_第2张图片

2>粘包问题

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

粘包问题及解决_第3张图片

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

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

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

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

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

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

3>粘包问题解析

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

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

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

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

    粘包问题及解决_第4张图片

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

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

4>解决粘包问题

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

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

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

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

    粘包问题及解决_第5张图片

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

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

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

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

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

粘包问题及解决_第6张图片

    客户端的写法

粘包问题及解决_第7张图片

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

粘包问题及解决_第8张图片

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

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

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

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

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

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

    5>发送真实数据。

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

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

    服务端代码如下

粘包问题及解决_第9张图片

客户端

粘包问题及解决_第10张图片

你可能感兴趣的:(python学习)