ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

带有神秘缓冲区的套接字

2019-11-22 15:08:32  阅读:246  来源: 互联网

标签:recv sockets python


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

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

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

没有数据丢失.但是显然在某个地方有一个缓冲区已被填充,套接字现在正在返回旧数据.但是,不应该只是继续返回直到缓冲区为空?取而代之的是,尽管已建立了数据包缓冲区,但它仅在收到新数据包时才返回.奇怪的!

这是代码的本质(这是用于非阻塞的,我也已经用recv完成了阻塞-同样的结果).为了简单起见,我剥离了所有的包装重组材料.我已经仔细地将其追溯到套接字,所以我知道这不应该受到指责.

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是基于流的协议,而不是基于消息的协议.它不保留消息边界.这意味着您不能期望每条消息有一个recv()调用.如果您以突发方式发送数据,则Nagle’s algorithm会将数据合并为一个TCP数据包.

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

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

如果您有可变长度的消息,则需要自己跟踪消息边界. TCP不会像UDP那样为您做这件事.这意味着将包含消息长度的标头添加到每个消息的开头.

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

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

标签:recv,sockets,python
来源: https://codeday.me/bug/20191122/2060676.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有