为Blender3D Python脚本应用setblocking(0)时的索引器
我目前正在运行一个使用Blender3D的脚本,我在Stackoverflow的帮助下从Python2+移植到Python3+。该脚本在欧姆龙PLC(可编程逻辑计算机)和Blender/Python3+之间创建通信。该脚本使用TCP通信来写入和读取PLC的内存。端口后,脚本在Blender中正常运行唯一的问题是它会造成大量延迟,并迫使Blender以6 fps的速度运行 默认情况下,Python套接字是阻塞的。这意味着,当您调用为Blender3D Python脚本应用setblocking(0)时的索引器,python,sockets,tcp,blender,Python,Sockets,Tcp,Blender,我目前正在运行一个使用Blender3D的脚本,我在Stackoverflow的帮助下从Python2+移植到Python3+。该脚本在欧姆龙PLC(可编程逻辑计算机)和Blender/Python3+之间创建通信。该脚本使用TCP通信来写入和读取PLC的内存。端口后,脚本在Blender中正常运行唯一的问题是它会造成大量延迟,并迫使Blender以6 fps的速度运行 默认情况下,Python套接字是阻塞的。这意味着,当您调用socket.read()时,函数将不会返回,直到您的数据被读取或s
socket.read()
时,函数将不会返回,直到您的数据被读取或socket上出现错误。i、 e.套接字“阻止”执行,直到操作完成。由于您的代码在recv()
调用中被阻止,您的游戏将冻结。”
在该链接中,如果您添加setblocking(0)
或setblocking(False)
或settimeout(0)
(同样的事情),您将取消TCP通信引起的延迟
为了使其正常工作,我必须尝试包装我的recv()
调用,但为了避免套接字错误:BlockingIOError:[WinError 10035]非阻塞套接字操作无法立即完成
我是这样做的:
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。但当我打开它时,它会给我一个索引器:
文件“D:\…”,第126行,反汇编格式
asm[b'ICF']=binstr2int(self.rawTcpFrame[16])
索引器:索引超出范围“
这是错误发生的区域,如果我注释掉该行,它只会说错误发生在下一个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
可以找到整个脚本您的消息不够长(序列短于17)。您应该测试帧的长度,或者使用
zip
和slice确保您不会尝试调用不存在的索引:
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:…中,但索引器除外:
,并在那里处理过短的帧。我不确定我是否做对了,但它会导致更多错误。我尝试过将它们包装在try中,但这会与其他内容相混淆:文件“D:\…”,第177行,在u str_uu中返回b“”。连接([k+b':')+字节(str(asm[k]),'utf-8')+b''表示列表中的k(asm.keys()))))。decode('utf-8')AttributeError:'NoneType'对象没有属性'keys'
这会弄乱程序中的另一行,请检查我问题下的注释。谢谢。您可能应该返回{}
在您的除…
子句中,如果您决定捕获错误,而不是使用zip
/slice方法。在某个地方,您需要决定如何处理丢失的数据,这取决于您决定在何处以及如何处理。但这是另一个问题,值得提出新的问题。请确保您下次做好准备。。。