簡體   English   中英

套接字分段接收數據

[英]Socket Fragmented Received Data

我正在嘗試創建某種客戶端監視器,例如終端,以通過以太網從串行設備接收數據。 我正在嘗試將套接字與 python 一起使用,但是當我創建連接時問題就出現了。 我應該只收到來自服務器的一條消息,我收到了整條消息,但分成了兩個數據包,如下所示:

消息預期:

   b'-- VOID MESSAGE--'

收到消息:

   b'-- VOID'
   b' MESSAGE--'

我不知道這是否是緩沖區大小、解碼或任何其他功能的問題

import socket        

TCP_IP = '192.168.#.#'
TCP_PORT = ### 
BUFFER_SIZE = 1024
data1=' '

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((TCP_IP, TCP_PORT))

while(1):
    data = s.recv(BUFFER_SIZE)
    print(data.decode('ASCII'))


s.close()

我已經嘗試過一些編解碼器選項,如 UTF-8、UTF-16 和 ASCII,但我仍然得到相同的結果。


這個功能幫助我解決了這個問題。

while(1):                                           
    cadena += s.recv(1)                            
    if (((cadena)[i])=='\n'):       
        print(cadena.decode('ASCII'))               
        cadena=b''                                  
        i=-1                                        

    i+=1 

正如已經說過的那樣 - 這就是套接字的工作方式。 發送的數據可以拆分為塊。 因此,如果您想確定已收到發送的完整消息,則需要實現某種協議,其中一部分將包含消息的長度。 例如:

  • 前四個字節(整數)表示消息的長度
  • 其他字節 - 消息的內容

在這種情況下,發送消息的算法將如下所示:

  • 計算消息的長度
  • 使用消息長度寫入套接字整數(4 個字節)
  • 寫入消息的套接字內容

和閱讀算法:

  • 從套接字讀取字節並將讀取數據寫入累加器緩沖區
  • 從緩沖區讀取前四個字節作為整數 - 這將是消息長度
  • 檢查緩沖區長度是否大於或等於“{message length} + 4”
  • 如果它然后讀取所需的字節數,這將是發送的消息。
  • 從緩沖區中刪除第一個“{message length} + 4”字節
  • 從第二點重復
  • 如果沒有足夠的字節讀取消息內容,則從第一點開始重復。

如果您可以忍受這些限制,則一種解決方案是使用 UDP 而不是 TCP:

  1. 有大小限制,數據必須適合一個數據包
  2. UDP 是“不可靠的”。

TCP 連接傳輸一個字節流。 OTOH UDP 傳輸單個數據報(消息)。 如果發送方發送 N 個數據報,接收方將收到相同的 N 個數據報。 也許亂序,也許有些會丟失,但每個數據報都是獨立的。

關於限制,這些不是那么簡單的問題。 有關這些主題的信息很多,只需搜索即可。

最大大小取決於 IPv4 或 IPv6、碎片等因素,有最好的情況和最壞的情況。 通常,您可以假設一個以太網幀(對於所有標頭 + 有效負載)絕對沒有問題。

“不可靠”並不意味着傳輸質量很差。 網絡應該在“盡力而為”的基礎上工作。 這意味着沒有 ACK、超時和重傳。 你可以沒有它,或者你可以在你的協議中添加簡單的 ACK。

你可以使用這個例子。

服務器代碼:(從客戶端讀取)

#!/usr/bin/python3

from socket import socket, gethostname

s = socket()
host = gethostname()
port = 3399
s.bind((host, port))
s.listen(5)

while True:
    print("Listening for connections...")
    connection, addr = s.accept()

    try:
        buffer = connection.recv(1024)

        response = ''

        while buffer:                
            response += buffer.decode('ASCII')
            buffer = connection.recv(1024)

        print(response)
        connection.close()


    except KeyboardInterrupt:
        if connection:
            connection.close()
        break

客戶端代碼:(發送消息)

#!/usr/bin/python3

from socket import socket, gethostname

s = socket()
host = gethostname()
port = 3399

s.connect((host, port))

print("Sending text..")

s.sendall(b'-- VOID MESSAGE--')

print("Done sending..")
s.close()

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM