简体   繁体   中英

Non-Blocking error when adding timeout to python server

I am writing a simple TCP server in python, and am trying to input a timeout. My current code:

import socket


def connect():
    HOST = ''                 # Symbolic name meaning the local host
    PORT = 5007             # Arbitrary non-privileged port
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    s.bind((HOST, PORT))
    s.listen(1)
    s.settimeout(5)
    conn, addr = s.accept()
    print 'Connected by', addr
    return conn

conn = connect()

while 1:
    data = conn.recv(1024)
    if not data: break
    print data
conn.close()

Issue is when I try to connect I get an error at data = conn.recv(1024)

error: [Errno 10035] A non-blocking socket operation could not be completed immediately

Code works without the timeout.

You can turn on blocking:

    # ...
    conn.setblocking(1)
    return conn
# ...

Ran into the same problem 30 minutes ago. Found a simple non-elegant work around...if you give the socket time to breathe by doing time.sleep(1), catching the 10035 error and doing a retry it works. I'm using 2.7.5...maybe this is a bug that got fixed. Not real sure.

Code sample...please understand this is very simplistic test code I use (only recv 1 byte at a time).So where 's' is the socket with a 10s timeout and 'numbytes' is number of bytes I need...

def getbytes(s,numbytes):
     din = ''
     socketerror10035count = 0
     while True:
          try:
               r = s.recv(1).encode('hex')
               din += r
               if len(din)/2 == numbytes:
                    print 'returning',len(din)/2, 'bytes'
                    break
          except socket.timeout as e:
               din = 'socket timeout'
               break
          except socket.error as e:
               if e[0] == 10035 and socketerror10035count < 5:
                    socketerror10035count = socketerror10035count  +1
                    time.sleep(1)
               else:
                    din = 'socket error'
                    break
          except:
               din = 'deaddead'
               break
     return din

Try to set the timeout on the socket and the blocking on the connection. Like this:

import socket 

def connect():
    HOST = ''                 # Symbolic name meaning the local host
    PORT = 5007             # Arbitrary non-privileged port
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    s.settimeout(5)
    s.bind((HOST, PORT))
    s.listen(1)  
    return s

s = connect()

while 1:
    conn, addr = s.accept()
    print 'Connected by', addr
    conn.setblocking(1)
    data = conn.recv(1024)
    conn.close()
    if not data: break
    print data
s.close()

For Python 3 and above, the above code which references e as a scriptable object will need to be changed to "e.errno". And, of course the print statements require parenthesis around the arguments.

Additionally, you may want to change the "except socket.error as e:" line to "except BlockingIOError as e:". However, the code works as is under Python 3.8.5 on Windows.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM