Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why am I getting a ConnectionResetError here?

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!

like image 468
gnargnagnar Avatar asked Apr 24 '15 07:04

gnargnagnar


People also ask

What causes ConnectionResetError?

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.

What is ConnectionResetError Python?

exception ConnectionResetError. A subclass of ConnectionError , raised when a connection is reset by the peer. Corresponds to errno ECONNRESET . exception FileExistsError. Raised when trying to create a file or directory which already exists.


1 Answers

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.

like image 102
dano Avatar answered Nov 15 '22 12:11

dano