Domanda

I'm currently running a script with Blender3D I ported from Python 2+ to Python 3+ with the help of someone from Stackoverflow. The script creates communication between a OMRON PLC (Programmable logic computer) and Blender/Python3+. The script uses TCP communication to write and read the PLC's memory. After the port the script ran properly in Blender the only problem it creates a massive amount of lag and forces Blender to run at 6 fps.

Python sockets are blocking by default. What that means is that when you call socket.read() the function will not return until your data has been read or there is an error on the socket. i.e. The socket "blocks" execution until the operation has completed. Because your code gets blocked in the recv() call, your game freezes." LINK

In the link there is said that if you add setblocking(0) or setblocking(False) or settimeout(0) (All the same thing), you will cancel the delay that is caused by the TCP communication.

In order to make it work I had to wrap my recv() call in a try, except in order to avoid a socket error: BlockingIOError: [WinError 10035] A non-blocking socket operation could not be completed immediately.

I've done it like this:

    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

However this didn't solve my problem, this creates more problems. The script will run fine but at 6fps when I have setblocking(1). But when I turn it on it gives me a Indexerror:

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

This is the area where the error occurs, if I comment out the line it will just say the error occurs in the next self.rawTcpFrame[17] for example:

    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

The entire script can be found here.

È stato utile?

Soluzione

Your message is not long enough (sequence is shorter than 17). You should test length of frame, or use zip and slice to be sure, you don't try to call index that does not exist:

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)

or you can wrap everything in try: ... except IndexError: and handle too short frame there.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top