gpt4 book ai didi

python - 带有神秘缓冲区的套接字

转载 作者:行者123 更新时间:2023-11-28 16:40:37 25 4
gpt4 key购买 nike

我正在构建一个基于 python 的接口(interface),用于通过 TCP 从仪器中提取数据。数据流作为特定事件出现,并且时间不稳定:我得到数据突发,然后是缓慢的时期。它们是小数据包,因此为简单起见,假设它们是完整的数据包。

这是我从套接字得到的行为:

  • 发送事件 #1:socket.recv 返回事件 #1
  • 发送事件 #2:socket.recv 返回事件 #2
  • 快速发送事件 #3-50:socket.recv 仅返回事件 #3-30(返回 27 次)
  • 缓慢发送事件 #51:socket returns.recv 事件 #31
  • 缓慢发送事件 #52:socket returns.recv 事件 #32

没有数据丢失。但显然某处有一个缓冲区已满,套接字现在正在返回旧数据。但是 recv 不应该一直返回直到缓冲区为空吗?相反,它只在收到新数据包时才返回,尽管已经建立了数据包缓冲区。奇怪!

这是代码的本质(这是非阻塞的,我也只用 recv 完成了阻塞——同样的结果)。为了简单起见,我剥离了所有数据包重组的东西。我已经仔细地追溯到 socket ,所以我知道这不是罪魁祸首。

class mysocket:
def __init__(self,ip,port):
self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.socket.connect((ip,port))
self.keepConn = True
self.socket.setblocking(0)
threading.Thread(target = self.rcvThread).start()
threading.Thread(target = self.parseThread).start()

def rcvThread(self):
while self.keepConn:
readable,writable,inError = select([self.socket],[self.socket],[],.1)
if readable:
packet = self.socket.recv(4096)
self.recvqueue.put_nowait(packet)
try:
xmitmsg = self.sendqueue.get_nowait()
except Queue.Empty:
pass
else:
if writable:
self.socket.send(xmitmsg)

def parseThread(self,rest = .1):
while self.keepConn:
try:
output = self.recvqueue.get_nowait()
eventnumber = struct.unpack('<H',output[:2]
print eventnumber
except Queue.Empty:
sleep(rest)

为什么我不能让套接字将所有数据转储到它的缓冲区中?我永远追不上!这个太奇葩了。有人指点一下吗?

我是一个业余爱好者,但我真的在这方面做了功课,但我完全不知所措。

最佳答案

packet = self.socket.recv(4096)
self.recvqueue.put_nowait(packet)

TCP 是一种基于流的协议(protocol),而不是基于消息的协议(protocol)。它不保留消息边界。这意味着您不能指望每条消息调用一次 recv()。如果你突发发送数据,Nagle's algorithm将数据组合成一个 TCP 数据包。

您的代码假定每个 recv() 调用返回一个“数据包”,并且解析线程打印每个“数据包”的第一个数字。但是 recv() 不返回数据包,它从 TCP 流返回数据 block 。这些 block 可以包含一条消息或多条消息甚至部分消息。无法保证前两个字节始终是事件编号。

通常,从 TCP 连接读取数据涉及多次调用 recv() 并将获得的数据存储在缓冲区中。收到完整消息后,您便会从缓冲区中删除适当数量的字节并进行处理。

如果您有可变长度的消息,那么您需要自己跟踪消息边界。 TCP 不像 UDP 那样为您做这件事。这意味着在每条消息的前面添加一个包含消息长度的 header 。

try:
xmitmsg = self.sendqueue.get_nowait()
except Queue.Empty:
pass
else:
if writable:
self.socket.send(xmitmsg)

另一方面,这段代码似乎有一个错误。无论套接字是否可写,它都会从发送队列中删除消息。如果套接字不可写,它会默默地丢弃消息。

关于python - 带有神秘缓冲区的套接字,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19738484/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com