6

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.

Richard
  • 15,152
  • 31
  • 85
  • 111
  • I really recomment the `SocketServer` module. It makes i easy to switch to multithreading etc. It is also used by the `SimpleHTTPServer` module. – User Oct 24 '13 at 19:00
  • 2
    Did you figure out why the exception is raised? – AmitE Mar 01 '16 at 14:17

4 Answers4

4

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()
VVV
  • 53
  • 5
  • 2
    It works, any idea why adding the timeout would cause the error in the first place? – user3582887 Mar 24 '16 at 14:12
  • 1
    Also, this error only occurs in Windows, When run on linux, the "conn.setblocking(1)" is not required and the timeout works as expected. – user3582887 Mar 24 '16 at 14:36
2

You can turn on blocking:

    # ...
    conn.setblocking(1)
    return conn
# ...
User
  • 14,131
  • 2
  • 40
  • 59
  • 2
    This doesn't explain at all why setting a timeout causes it to become non-blocking. It's certainly not in the python docs as far as I can find, and I'm curious why this is happens as well. – Fulluphigh Sep 13 '14 at 05:06
  • 5
    Actually setting a timeout makes it non-blocking. from the docs -> "s.settimeout(0.0) is equivalent to s.setblocking(0); s.settimeout(None) is equivalent to s.setblocking(1)." see https://docs.python.org/2/library/socket.html#socket.socket.settimeout – AmitE Mar 01 '16 at 14:15
1

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
JohnLaird
  • 111
  • 2
  • 12
0

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.