Why am I getting a ConnectionResetError here?

14,488

You're getting the exception because you're trying to write some data back to the client on the server-side, but the client is closing the socket immediately after sending in the 'echo', without actually receiving the response from the server. If a socket connection is closed while there is unreceived data on the wire, you'll get an error on the sending side, so that you know the remote side may not have received whatever you last sent.

The problem goes away if you add a call to socket.recv(1024) on the client-side prior to calling socket.close(), so that the client waits for a response from the server before closing the socket. You could also just use a try/except around the write call on the server-side if you just want to gracefully handle the exception, even when the client does the wrong thing.

Share:
14,488
gnargnagnar
Author by

gnargnagnar

Updated on July 26, 2022

Comments

  • gnargnagnar
    gnargnagnar almost 2 years

    I am new to Python 3 and am playing around with asyncio. Thereby, I am experiencing a strange behavior with the following server-side code:

    import asyncio
    
    
    @asyncio.coroutine
    def handle_client(reader, writer):
        print('Client connected.')
        client_connected = True
        while client_connected:
            print('Waiting for client event.')
            line = yield from reader.readline()
            if line:
                print('Got: {}'.format(line))
                if line.decode() == 'echo\n':
                    print('Sending back echo.')
                    writer.write(line)
                else:
                    print('Not sending back anything.')
            else:
                print('Client disconnected.')
                client_connected = False
    
    
    if __name__ == '__main__':
        asyncio.async(asyncio.start_server(handle_client, 'localhost', 8888))
        asyncio.get_event_loop().run_forever()
    

    When I run this client code (EDIT: client code is entered manually into an IPython session, the server definitely has time to write before I close the socket)...

    import socket
    client = socket.create_connection(('localhost', 8888))
    client.sendall('echo\n'.encode())
    client.close()
    

    ... I get an error traceback from the server:

    C:\Users\Gnar\Anaconda3\python.exe C:/Users/Gnar/Code/echo.py
    Client connected.
    Waiting for client event.
    Got: b'echo\n'
    Sending back echo.
    Waiting for client event.
    Task exception was never retrieved
    future: <Task finished coro=<handle_client() done, defined at C:/Users/Gnar/Code/echo.py:4> exception=ConnectionResetError(10054, 'An existing connection was forcibly closed by the remote host', None, 10054, None)>
    Traceback (most recent call last):
      File "C:\Users\Gnar\Anaconda3\lib\asyncio\tasks.py", line 234, in _step
        result = coro.throw(exc)
      File "C:/Users/Gnar/Code/echo.py", line 10, in handle_client
        line = yield from reader.readline()
      File "C:\Users\Gnar\Anaconda3\lib\asyncio\streams.py", line 425, in readline
        yield from self._wait_for_data('readline')
      File "C:\Users\Gnar\Anaconda3\lib\asyncio\streams.py", line 393, in _wait_for_data
        yield from self._waiter
      File "C:\Users\Gnar\Anaconda3\lib\asyncio\futures.py", line 386, in __iter__
        yield self  # This tells Task to wait for completion.
      File "C:\Users\Gnar\Anaconda3\lib\asyncio\tasks.py", line 287, in _wakeup
        value = future.result()
      File "C:\Users\Gnar\Anaconda3\lib\asyncio\futures.py", line 275, in result
        raise self._exception
      File "C:\Users\Gnar\Anaconda3\lib\asyncio\selector_events.py", line 662, in _read_ready
        data = self._sock.recv(self.max_size)
    ConnectionResetError: [WinError 10054] An existing connection was forcibly closed by the remote host
    

    The issue must be somehow in relation with writer.write, because when I call the following client code (which makes the server skip the writing), there is no error:

    import socket
    client = socket.create_connection(('localhost', 8888))
    client.sendall('foo\n'.encode())
    client.close()
    

    The corresponding server log:

    C:\Users\Gnar\Anaconda3\python.exe C:/Users/Gnar/Code/echo.py
    Client connected.
    Waiting for client event.
    Got: b'foo\n'
    Not sending back anything.
    Waiting for client event.
    Client disconnected.
    

    What am I missing? Am I using asyncio incorrectly?

    Thanks!