套接字收到的分段数据

3
我尝试创建一种客户端监视器,类似于终端,通过以太网从串行设备接收数据。我试图使用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 

5
这就是套接字的工作原理。即使一条消息被完整发送,也不能保证它会一次性到达。您必须继续读取直到全部接收完毕。 - John Gordon
1
你粘贴的代码没有接收或发送消息的代码,所以它不能正常工作并不奇怪。 - David Schwartz
好的,在代码行 data = s.recv(BUFFER_SIZE) 中,我正在接收数据。我知道这是因为我已经尝试过这段代码,我能够得到数据,但不是我需要的格式。 - Daniel Hernández
3个回答

2

如前所述,这就是套接字的工作原理。

发送的数据可以被分割成块。因此,如果您想确保已收到完整的消息,则需要实现某种协议,其中包含消息长度的部分。例如:

  • 前四个字节(整数)表示消息的长度
  • 其他字节 - 消息的内容

在这种情况下,发送消息的算法将如下:

  • 计算消息的长度
  • 向套接字写入带有消息长度的整数(4个字节)
  • 向套接字写入消息的内容

读取算法:

  • 从套接字中读取字节,并将读取的数据写入累加器缓冲区
  • 从缓冲区中读取前四个字节作为整数 - 它将是消息的长度
  • 检查缓冲区长度是否大于或等于“{message length} + 4”
  • 如果是,则读取所需数量的字节,那就是发送的消息。
  • 从缓冲区中删除前“{message length} + 4”个字节
  • 重复第二点
  • 如果没有足够的字节来读取消息内容,请从第一点重新开始。

1
一种解决方案是,如果您可以接受以下限制,则使用UDP而不是TCP:
  1. 有一个大小限制,数据必须适合一个数据包
  2. UDP是“不可靠的”。
TCP连接传输一个字节流。另一方面,UDP传输单个数据报(消息)。如果发送者发送N个数据报,则接收者将接收相同数量的N个数据报。可能无序,可能会丢失一些,但每个数据报都独立于其他所有数据报。
关于这些限制,这些并不是简单的问题。关于这些主题有大量的信息,只需搜索即可。
最大大小取决于诸如IPv4或IPv6、分段等因素,有最佳情况和最坏情况。通常可以假定一个以太网帧(用于所有头+有效负载)绝对没有问题。
“不可靠性”并不意味着传输质量很差。网络应该按“尽力而为”的原则工作。这意味着没有ACK、超时和重传。您可以在协议中添加简单的ACK或不需要它。

我同时从三个传感器读取数据,每一个传感器所接收到的数据对我的最终结果都有很大影响,这就是为什么我不能使用UDP的原因。UDP看起来非常有用,但如果我最终没有获得完整的数据,可能会给我带来严重的问题。 - Daniel Hernández

0
你可以使用这个例子。 服务器代码:(从客户端读取)
#!/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()

问题在于我无法控制服务器,我只能修改客户端,并且我需要做的就是接收来自服务器的所有数据,当然,以正确的结构。一开始我认为这很容易,但数据分段给我带来了问题。当然,我的客户端永远不会发送数据,只会获取和打印,仅此而已。谢谢你的帮助 :) - Daniel Hernández

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接