【问题标题】:Socket Fragmented Received DataSocket 分片接收数据
【发布时间】:2020-01-09 14:07:09
【问题描述】:

我正在尝试创建某种客户端监视器,例如终端,以通过以太网从串行设备接收数据。我正在尝试使用带有 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 

【问题讨论】:

  • 这就是套接字的工作原理。即使一条消息全部发送,也不能保证全部到达。您必须继续阅读,直到全部了解为止。
  • 您粘贴的代码没有任何接收或发送消息的代码,所以没有任何代码也就不足为奇了。
  • 好吧,行数据 = s.recv(BUFFER_SIZE) 是我接收数据的地方。我知道,因为我已经准备好尝试代码,并且我得到了数据,但不是我需要的格式。

标签: python python-3.x sockets tcp


【解决方案1】:

你可以使用这个例子。

服务器代码:(从客户端读取)

#!/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()

【讨论】:

  • 这里的问题是我无法控制服务器,我只有修改客户端的权力,我需要做的就是从服务器接收所有数据,显然,在正确的结构中。一开始我认为这很容易,但数据碎片化是什么给我带来了问题。当然,我的客户永远不会发送数据,只会获取和打印,仅此而已。谢谢你帮助我:)
【解决方案2】:

正如已经说过的 - 这就是套接字的工作原理。 发送的数据可以分成块。所以如果你想确定你已经收到了发送的整个消息,你需要实现某种协议,其中一部分将包含你的消息的长度。例如:

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

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

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

及阅读算法:

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

【讨论】:

    【解决方案3】:

    如果您能忍受这些限制,一个解决方案是使用 UDP 而不是 TCP:

    1. 有大小限制,数据必须适合一个数据包
    2. UDP 是“不可靠的”。

    一个 TCP 连接传输一个字节流。 OTOH UDP 传输单个数据报(消息)。如果发送方发送 N 个数据报,接收方将收到相同的 N 个数据报。也许乱序,也许有些会丢失,但每个数据报都是独立于所有其他数据报的。

    关于限制,这些不是那么简单的问题。有很多关于这些主题的信息,只需搜索即可。

    最大大小取决于 IPv4 或 IPv6、分段等因素,并且存在最佳情况和最差情况。通常,您可以假设一个以太网帧(对于所有标头 + 有效负载)绝对没有问题。

    “不可靠”并不意味着传输质量很差。网络应该在“尽力而为”的基础上工作。这意味着没有 ACK、超时和重传。你可以没有它,也可以在你的协议中添加简单的 ACK。

    【讨论】:

    • 我同时从三个传感器读取数据,从每个传感器接收到的数据对我的最终结果有很大影响,这就是我不能使用 UDP 的原因。看起来很有用,但如果我最后没有得到完整的数据,可能会给我带来一些严重的问题。
    猜你喜欢
    • 2018-04-20
    • 2015-07-31
    • 2013-07-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-11-29
    相关资源
    最近更新 更多