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

本文涉及的产品
全局流量管理 GTM,标准版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
云解析 DNS,旗舰版 1个月
简介: Python Socket API参考出处:http://blog.csdn.net/xiangpingli/article/details/47706707   使用socket.recv(pack_length)接收不定长的数据,如果数据包长度超过一定值,则接收的数据不全,同时还会多触发一次 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

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

 

 

个人注解:

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

 

相关文章
|
3月前
|
网络协议 安全 Java
Java网络编程入门涉及TCP/IP协议理解与Socket通信。
【6月更文挑战第21天】Java网络编程入门涉及TCP/IP协议理解与Socket通信。TCP/IP协议包括应用层、传输层、网络层和数据链路层。使用Java的`ServerSocket`和`Socket`类,服务器监听端口,接受客户端连接,而客户端连接指定服务器并交换数据。基础示例展示如何创建服务器和发送消息。进阶可涉及多线程、NIO和安全传输。学习这些基础知识能助你构建网络应用。
43 1
|
1月前
|
监控 Python Windows
Python如何接收键盘按键
根据你的应用场景(控制台应用、GUI应用或需要监控按键事件的应用),可以选择适当的方法来接收键盘输入。对于交互式命令行脚本,`input()`或 `getch`类函数通常就足够。对于更复杂的键盘交互,如监控全局按键或构建含有图形用户界面的应用程序,则需要使用如 `pynput`或GUI特有的库函数来实现。
25 1
|
1月前
|
网络协议 数据格式 Python
python Socket无限发送接收数据方式
Socket是指套接字,是对网络中不同主机上的应用进程之间进行双向通信的端点的一种抽象。 一个套接字就是网络上进程通信的一端,提供了应用层进程利用网络协议交换数据的机制。
|
1月前
|
网络协议 Java
一文讲明TCP网络编程、Socket套接字的讲解使用、网络编程案例
这篇文章全面讲解了基于Socket的TCP网络编程,包括Socket基本概念、TCP编程步骤、客户端和服务端的通信过程,并通过具体代码示例展示了客户端与服务端之间的数据通信。同时,还提供了多个案例分析,如客户端发送信息给服务端、客户端发送文件给服务端以及服务端保存文件并返回确认信息给客户端的场景。
一文讲明TCP网络编程、Socket套接字的讲解使用、网络编程案例
|
22天前
|
网络协议 Linux
TCP 和 UDP 的 Socket 调用
【9月更文挑战第6天】
|
1月前
|
网络协议
socket编程(2) -- TCP通信
socket编程(2) -- TCP通信
33 0
|
2月前
|
网络协议 Java
如何在Java中使用Socket编程实现TCP连接?
在Java中,通过Socket编程实现TCP连接非常常见。以下演示了基本的TCP通信流程,可根据具体需求进行扩展。
115 0
|
3月前
|
Java Android开发
Java Socket编程示例:服务器开启在8080端口监听,接收客户端连接并打印消息。
【6月更文挑战第23天】 Java Socket编程示例:服务器开启在8080端口监听,接收客户端连接并打印消息。客户端连接服务器,发送&quot;Hello, Server!&quot;后关闭。注意Android中需避免主线程进行网络操作。
72 4
|
3月前
|
前端开发 API Python
如何在Python中接收前端POST上传的文件
如何在Python中接收前端POST上传的文件
340 2
|
3月前
|
网络协议
逆向学习网络篇:通过Socket建立连接并传输数据
逆向学习网络篇:通过Socket建立连接并传输数据
42 0