• Python3的tcp socket接收不定长数据包接收到的数据不全。


    Python Socket API参考出处: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/python
    
    import socket
    
    SEND_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
    

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

    个人注解:

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

  • 相关阅读:
    192021
    191020
    magento注册
    magento登陆
    把PHP的数组变成带单引号的字符串
    magento直接操作数据库
    兼容各大浏览器的event获取
    手动修改magento域名
    微信支付中的jsapi返回提示信息
    CentOS 下安装xdebug
  • 原文地址:https://www.cnblogs.com/ribavnu/p/4816919.html
Copyright © 2020-2023  润新知