python套接字接收超时未超时

np8igboo  于 2022-12-05  发布在  Python
关注(0)|答案(1)|浏览(128)

Synopsis: server hangs on socket.recv() even though a socket.settimeout() was set.
Have a simple socket based server that loops over commands (simple text messages) sent from client(s) until it receives an 'end' command. I simulate a broken client by - making a connection - sending a command - receive the result - exit (never sending the 'end' command to server)
The whole system worked perfectly when the server/client protocol was adhered to, but with the broken client simulation the server is NOT timing out on the recv.
Relevant server code (simplified):

ip = '192.168.77.170'
port = 12345
args = { app specific data }

with socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0) as serverSock:
    serverSock.bind((ip, port))
    serverSock.listen()
    while True:
        sock, addr = serverSock.accept()
        thread = threading.Thread(target=session, args=(sock, args))
        thread.name = "client {}".format(addr)
        thread.daemon = True
        thread.start()

def session(sock, args):
    sess = threading.local()
    sess.sock = sock
    sess.__dict__.update(args)

    print("-" * 60)
    print("Session opened   from={addr}.".format(addr=sock.getpeername()))
    sock.settimeout(10.0)
    while True:
        try:
            print('about to wait on recv', sock.gettimeout())
            cmd = recvString(sock)
            print('got cmd =', cmd)
            if   cmd.startswith('foo'):  doFoo(sess, cmd)
            elif cmd.startswith('bar'):  doBar(sess, cmd)
            elif cmd.startswith('baz'):  doBaz(sess, cmd)
            elif cmd.startswith('end'):  break
            else:
                raise Exception("Protocol Error: bad command '{}'".format(cmd))
        except TimeoutError as err:
            print("Error protocol timeout")
            break
        finally:
            try:
                sock.close()
            except:
                pass
            print("Session closed.")

def recvString(sock):
    buff = bytearray()
    while True:
        b = sock.recv(1)
        if b == b'\x00': break
        buff += b
    return buff.decode() if len(buff) else ''

When running with broken client I get

> about to wait on recv cmd 10.0
> got cmd = foo
> about to wait on recv cmd 10.0

waits forever (and has very high CPU consumption to add insult to injury)
I've RTFM'd thoroughly and multiple times, and looked at other similar SO postings and all indicate that a simple settimeout() should work. Can't see what I'm doing wrong. Any help greatly appreciated.

vwkv1x7d

vwkv1x7d1#

while True:
    b = sock.recv(1)
    if b == b'\x00': break
    buff += b

如果对等体关闭连接,则sock.recv(1)将返回b'',即没有数据。这种情况没有考虑在内。结果将出现一个无休止的忙碌循环,其中sock.recv(1)将返回b'',然后再次被调用,并立即返回b''等。这也解释了高CPU。

相关问题