博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
一个完整的socket recv()案例,包括解决粘包、服务器主动推数据的问题
阅读量:5085 次
发布时间:2019-06-13

本文共 2062 字,大约阅读时间需要 6 分钟。

前言:

本文是针对socket长连接(涉及到服务器主动推数据),每个包头的拼接算法和长度都不一样,具体的包头小伙伴们问自己公司的开发吧,本文只是提供思路。再啰嗦一句:recv到的包头中数字进行某种运算后得到的就是开发定义的返回code。

粘包问题解决思路:

python中的socket recv()是阻塞接收的,所以不存在同时发送多个数据接收错乱的情况。网上对于粘包有各种各样的解决办法,什么每次recv前sleep几秒,保证缓存中有足够数据在接收。还有说在recv()中加个wait的参数,保证每次都接受满1024个数据长度。我觉得网上唯一正确的办法是:先知道自己想要接收的数据的大小,然后用一个死循环接收完所有数据。

作者一开始是使用静态拆包的方式,就是每次send后都recv一次,然后把每次recv的结果都拼在一起,然后再根据包头中的包体长度拆出一个个完整包。这种方式有个缺点:如果后面的请求需要用到前面请求返回值做参数,那么就凉凉了。

这时候就需要用到动态拆包,send一个请求recv一个返回结果,然后解析出完整数据。但是实现的过程中发现几个问题:

(1)返回数据的长度跟我从包头里得到的长度不一致,我以为是粘包导致的接收不全,因为我后来加了个一样的请求,就能接收全了。

(2)后来我在每个请求发送前都加了sleep(10),第16个请求接受全了,但是后面的数据直接报错了。

(3)后来偶然一次,我发现能运行成功不报错,但是在大部分时运行会报错。

(4)然后发现send一个请求,返回了两个完整的包。

结合上面的四个问题,我开始了漫长的寻求解答的过程,后来得高人解答,才发现了问题——服务器主动推了数据。现在想想上面4点可不就是服务器主动推数据的表现嘛。

 

下面直接上方法,同时解决粘包、服务器主动推数据的问题。

思路:send之后,先recv(8)包头,得到包体大小,然后用死循环recv全。然后要用包头算法对得到的返回数据进行判断,进一步保证了这个包就是我需要的数据包。

 

1 def sendData(self, data, t, respHeader): 2         self.data = data 3         self.t = t 4         self.respHeader=respHeader 5         self.s.send(data)  # 传输包装好的请求 6         total_data = bytes() 7         header = 1 8  9         for i in range(5):  #每次send,我规定它最多去recv5次,以防浪费时间10             header_bytes = self.s.recv(8)  # 先接收包头11             body_len = struct.unpack("!2I", header_bytes)[0] #这是包体长度12             header = struct.unpack("!2I", header_bytes)[1] #开发定义的用来做运算13             print("应该接收的长度:", body_len)14             while len(total_data) < body_len:15                 total_data += self.s.recv(body_len)16                 print("实际接收的长度:", len(total_data))17             18             header_code = header & 0x3xxxxxxx  #做运算得到返回请求的code19             print("header_code: " + str(header_code))20             #如果算出来等于这个返回请求的头或者返回error,跳出for循环,不再继续recv21             if header_code == int(respHeader) or header_code == 1: 22                 print("over")23                 break24            else:25             #如果接收的不是我需要的包头,清空total_data,重新for循环从缓存中recv数据26                 total_data = bytes()27          if i >= 5:28             print("返回数据有误")

 

转载于:https://www.cnblogs.com/lucio1128/p/10692553.html

你可能感兴趣的文章
IPV6测试方法
查看>>
微信小程序--TabBar不出现
查看>>
JDBC核心API
查看>>
37. 解数独
查看>>
iOS 图片压缩
查看>>
AppStore提审app注意,不断更新
查看>>
20155204 2016-2017-2 《Java程序设计》第7周学习总结
查看>>
Inpute
查看>>
数据降维和可视化
查看>>
接口开发注意传参问题
查看>>
k8s基本概念
查看>>
Visual Studio快捷键
查看>>
FORM开发相关技术(二)
查看>>
对Map按key和value分别排序
查看>>
win8系统添加开机自启动软件的方法(转)
查看>>
C# 向下遍历删除子目录和子文件 及 向上遍历空的父目录
查看>>
Xcode5最初级的教程
查看>>
asp.net mvc 3.0 知识点整理 ----- (4).asp.net mvc 3 和asp.net mvc 4 对比
查看>>
滑行的窗口
查看>>
Dijkstra优先队列模板
查看>>