【问题标题】:IndexError when applying setblocking(0) for a Blender3D Python script为 Blender3D Python 脚本应用 setblocking(0) 时出现 IndexError
【发布时间】:2014-06-09 12:16:08
【问题描述】:

我目前正在使用 Blender3D 运行一个脚本,我在 Stackoverflow 的帮助下从 Python 2+ 移植到 Python 3+。该脚本在 OMRON PLC(可编程逻辑计算机)和 Blender/Python3+ 之间创建通信。该脚本使用 TCP 通信来写入和读取 PLC 的内存。移植后,脚本在 Blender 中正常运行,唯一的问题是它会产生大量延迟并迫使 Blender 以 6 fps 运行。

默认情况下,Python 套接字是阻塞的。这意味着当您调用socket.read() 时,该函数将不会返回,直到您的数据被读取或套接字上出现错误。即套接字“阻止”执行,直到操作完成。因为您的代码在 recv() 调用中被阻止,所以您的游戏冻结了。”LINK

链接中有说如果你添加setblocking(0)setblocking(False)settimeout(0)(都是一样的),你将取消由TCP通信引起的延迟。

为了使它工作,我不得不尝试将我的recv() 调用包装起来,除非为了避免套接字错误:BlockingIOError: [WinError 10035] A non-blocking socket operation could not be completed immediately

我是这样做的:

    def _recieve(self):
    try:
        pr = self.sock.recv(8)
        length = binstr2int( pr[4:8])
        r = pr + self.sock.recv( length)
        #print (' Recv:' + repr(r))
        return r
    except socket.error as err:
        # Any error but "Would block" should cause the socket to close
        if err.errno != errno.EWOULDBLOCK:
            self.sock.close()
            self.sock = None
            return

然而这并没有解决我的问题,这会产生更多的问题。当我有 setblocking(1) 时,该脚本将运行良好,但速度为 6fps。但是当我打开它时,它会给我一个 Indexerror:

File "D:\...", line 126, in disassembled asm[ b'ICF'] = binstr2int( self.rawTcpFrame[16]) IndexError: index out of range'

这是发生错误的区域,如果我注释掉该行,它只会说错误发生在下一个self.rawTcpFrame[17] 例如:

    def disassembled(self):
    asm = {
           b"header"   : binstr2int( self.rawTcpFrame[ 0: 4] ),
           b'length'   : binstr2int( self.rawTcpFrame[ 4: 8] ),
           b'command' : binstr2int( self.rawTcpFrame[ 8:12] ),
           b'errCode' : binstr2int( self.rawTcpFrame[12:16] ),
    }
    if( asm[b'command'] == 2) :
        asm[ b'ICF'] = binstr2int( self.rawTcpFrame[16])
        asm[ b'RSV'] = binstr2int( self.rawTcpFrame[17])
        asm[ b'GCT'] = binstr2int( self.rawTcpFrame[18])
        asm[ b'DNA'] = binstr2int( self.rawTcpFrame[19])
        asm[ b'DA1'] = binstr2int( self.rawTcpFrame[20])
        asm[ b'DA2'] = binstr2int( self.rawTcpFrame[21])
        asm[ b'SNA'] = binstr2int( self.rawTcpFrame[22])
        asm[ b'SA1'] = binstr2int( self.rawTcpFrame[23])
        asm[ b'SA2'] = binstr2int( self.rawTcpFrame[24])
        asm[ b'SID'] = binstr2int( self.rawTcpFrame[25])
        asm[ b'MRC'] = binstr2int( self.rawTcpFrame[26])
        asm[ b'SRC'] = binstr2int( self.rawTcpFrame[27])
        if self.fromRaw :
            #decode from response
            asm[ b'MRES'] = binstr2int( self.rawTcpFrame[28])
            asm[ b'SRES'] = binstr2int( self.rawTcpFrame[29])
            asm[b'response'] = self.rawTcpFrame[30:]
        else :
            asm[b'cmd'] = self.rawTcpFrame[28:]
    return asm

整个脚本可以在here.找到

【问题讨论】:

  • 我不确定我是否做对了,但这会导致更多错误。我已经尝试将它们包装在 try 中,但是这会与其他东西混淆:File "D:\...", line 177, in __str__ return b''.join([ k + b':' + bytes(str(asm[k]), 'utf-8') + b' ' for k in list(asm.keys())]).decode('utf-8') AttributeError: 'NoneType' object has no attribute 'keys'

标签: python sockets tcp blender


【解决方案1】:

您的消息不够长(序列短于 17)。您应该测试帧的长度,或者使用zip 和切片来确定,您不要尝试调用不存在的索引:

tags = (b'ICF', b'RSV', b'GCT', 
    b'DNA', b'DA1', b'DA2', 
    b'SNA', b'SA1', b'SA2', 
    b'SID', b'MRC', b'SRC')

for tag, data in zip(tags, self.rawTcpFrame[16:]):
    asm[tag] = binstr2int(data)

或者您可以将所有内容都包裹在try: ... except IndexError: 中并在那里处理太短的帧。

【讨论】:

  • 这与程序中的不同行混淆了,请检查我的问题下的评论。谢谢。
  • 如果您决定捕获错误而不是使用 zip / 切片方法,您可能应该在 except... 子句中返回 {}。在某个地方,您需要决定如何处理丢失的数据,而这取决于您决定在哪里以及做什么。但这是另一个问题,值得提出新问题。下次一定要准备好sscce.org...
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-12-09
  • 2021-10-12
  • 2015-04-13
  • 1970-01-01
  • 1970-01-01
  • 2019-08-23
  • 2014-03-01
相关资源
最近更新 更多