博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Python3的tcp socket接收不定长数据包接收到的数据不全。
阅读量:6951 次
发布时间:2019-06-27

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

:http://blog.csdn.net/xiangpingli/article/details/47706707

 

使用socket.recv(pack_length)接收不定长的数据,如果数据包长度超过一定值,则接收的数据不全,同时还会多触发一次 socket.recv().

 

参照python3.4的文档可发现:

socket.recv(bufsize[, flags])

Receive data from the socket. The return value is a bytes object representing the data received. The maximum amount of data to be received at once is specified by bufsize.

 

 

上述的英文的大体意思为:从socket中接收数据。返回值是byts类型。接收的最大数量的byte为指定的bufsize.

 

root@iZ94nil6ddfZ:~# cat setsockopt_test.py        #!/usr/bin/pythonimport socketSEND_BUF_SIZE = 4096 # 发送缓冲区的大小RECV_BUF_SIZE = 4096 # 接收缓冲区的大小def modify_buff_size():    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)    bufsize = sock.getsockopt(socket.SOL_SOCKET, socket.SO_SNDBUF)    print "Buffer size [Before]: %d" %bufsize    sock.setsockopt(socket.SOL_TCP, socket.TCP_NODELAY, 1)    sock.setsockopt(socket.SOL_SOCKET, socket.SO_SNDBUF, SEND_BUF_SIZE)    sock.setsockopt(socket.SOL_SOCKET, socket.SO_RCVBUF, RECV_BUF_SIZE)        bufsize = sock.getsockopt(socket.SOL_SOCKET, socket.SO_SNDBUF)    print( "Buffer size [After]: %d" %bufsize)if __name__ == '__main__':    modify_buff_size()

 

执行  

  bufsize = sock.getsockopt(socket.SOL_SOCKET, socket.SO_SNDBUF)

得到电脑上的默认接收缓冲区的值为:8192

 

问题场景描述:

server端是erlang实现的,client端是Python3实现的,通讯协议为自定义的格式,每次交互的数据包都是不定长的数据包。

从server端取数据,因为没有指定查询条件,返回的数据的数据量在1000条左右,每一条的数据都包含多个的整数型和字符串型,byte大小为:26782。

如果取得的数据量比较多,每一次的请求数据,client 的socket.recv(packet_size)会执行多次。

 

解决方案:

receiverBufsize = self._client_socket.getsockopt(                                    socket.SOL_SOCKET,                                     socket.SO_RCVBUF)                 data_body = None            if receiverBufsize < pack_length:                                data_body = bytes()                left_pack_length = pack_length                while left_pack_length > 0:                                        if left_pack_length > receiverBufsize:                        body_part =self._client_socket.recv(receiverBufsize)                     else:                        body_part =self._client_socket.recv(left_pack_length)                     data_body  +=  body_part                     left_pack_length -= receiverBufsize                            else:                data_body= self._client_socket.recv(pack_length)

 

 

个人注解:

Python的socket一次最多只能读出缓冲区的全部的数据,如果指定的数据包的大小大于缓冲区的大小,则读出的有效数据仅仅为缓冲区的数据。

如果能确定发送过来的数据大于缓冲区的大小,则需要多次:socket.recv(receiverBufsize),然后将收到的数据拼接成完整的数据包后再解析。

 

 

二次错误修正:

使用上边的解决方案,在收到较大的数据的时候,偶尔会出现 :

一个数据包读出来了,但是数据包的较靠后的一部分数据有问题,将数据包解析后发现只有前边的部分能正确解析、后边的部分解析出来全是无效的数据。同时还会多触发几次 socket.recv().

 

body_part =self._client_socket.recv(pack_length) body_part_length = len(body_part)  # body_part_length 、left_pack_length、以及上边提到的缓冲区的大小,这三个值都不一样大。

缓冲区,bufsize: 8192

下列的两个值是我电脑传输特定的数据包的时候的值:

pack_length :26782

body_part_length: 24460

 

 

热闹了,。。。。。函数api有问题

 

二次解决方案:

had_received = 0                 data_body = bytes()              while had_received < pack_length:                    part_body= self._client_socket.recv(pack_length - had_received)                    data_body +=  part_body                    part_body_length = len(part_body)                    #print('part_body_length', part_body_length)                    had_received += part_body_length

手动点击测试 :至少在五分钟内的连续点击测试并没有出现第一次的解决方案的的部分数据无效的情况。

 

 

个人注解:

  未能确定出错的原因,个人猜测:对缓冲区的读数据尽量少次数的读吧。。。。。。

 

转载于:https://www.cnblogs.com/ribavnu/p/4816919.html

你可能感兴趣的文章
纯js实现10分钟倒计时
查看>>
敏捷实践简单分享补充
查看>>
Apple Push Notification service
查看>>
Linux下修改Mysql的用户(root)的密码
查看>>
python学习笔记之常用操作符
查看>>
poj 3126 Prime Path (bfs)
查看>>
事件代理
查看>>
[Influxdb]记录
查看>>
图的最小生成树(普利姆prim算法)
查看>>
干货:实现数据可视化的几个工具选择(工具+编程语言)
查看>>
分享职场心得《10》
查看>>
NYoj 685 查找字符串
查看>>
noip普及组2018T2 龙虎斗
查看>>
sql 事物以及回滚
查看>>
drawrect&layoutsubviews
查看>>
程序中如何获取Android的Root权限
查看>>
算法策略的总结
查看>>
[转]Core Audio
查看>>
UIScrollView的属性总结
查看>>
unicode 和utf-8,GBK编码
查看>>