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

手動點擊測試 :至少在五分鍾內的連續點擊測試並沒有出現第一次的解決方案的的部分數據無效的情況。

 

 

個人注解:

  未能確定出錯的原因,個人猜測:對緩沖區的讀數據盡量少次數的讀吧。。。。。。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM