python3 terminal code runs fine, but the script does not

51 Views Asked by At

When using the Python3 CLI in the Linux terminal by simply calling 'python3' I am able to run and execute the socket code shown below to send a command to a netcat server running on a sensor on my network and I receive the expected return value:

#! /usr/bin/python3
import socket
import time

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(('192.168.50.30', 7501))
s.setblocking(True)
snd = s.send(b'\x00\x0dget_sensor_info')
rec = s.recv(1024, 0x40)
print(rec)

when I run this same exact code in a script like so: 'python3 test_sensor.py'. this returns the following error:

Traceback (most recent call last): File "ouster_uptimme.py", line 9, in rec = s.recv(1024, 0x40) BlockingIOError: [Errno 11] Resource temporarily unavailable

I am honestly very confused about what is going on here. this is not my first foray into sockets but I'm thinking there might be something going on from either timing or access level issue.

Open to ideas at this point I have spent a few hours trying to solve this problem and am open to outside input.

1

There are 1 best solutions below

3
srn On

Like @SteffenUllrich said in the comments, the issue here is using the 0x40 (MSG_DONTWAIT) flag.

You can actually replicate the error in your interactive python shell by defining the relevant part as a function:

>>> def foo():
    snd = s.send(b'\x00\x0dget_sensor_info')
    rec = s.recv(1024, 0x40)
    print(rec)
...
BlockingIOError: [Errno 11] Resource temporarily unavailable 

The reason you don't see it when pasting line by line is that this immediately is not actually immediately. The time passing between copy, paste and enter is apparently enough for the packet to arrive. Otherwise you'd get the same error. You can see the same behavior, if you time.sleep() a bit before recv and it would work in your script (just to see that this is the issue, it's at least unreliable for actual code).

Some context:

You're getting socket.errno.EAGAIN / socket.errno.EWOULDBLOCK (errno 11) and per docs those are mapped to the exception BlockingIOError.

This is happening due to using the 0x40 flag, which is hex for MSG_DONTWAIT. This sets the call to non-blocking. While you've set your open file descriptor to blocking, you do the inverse for the recv call. If s.recv does not find any data already present in the buffer, it will raise the aforementioned exception.

An operation that would block was attempted on an object that has non-blocking mode selected. Trying the same operation again will block until some external condition makes it possible to read, write, or connect (whatever the operation).