Jestem nowy w Pythonie 3 i bawię się z asyncio. W ten sposób, jestem przeżywa dziwne zachowanie z następującego kodu po stronie serwera:Dlaczego otrzymuję tutaj błąd ConnectionResetError?
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()
Kiedy uruchomić ten kod klienta (EDIT: Kod klient jest wprowadzany ręcznie do sesji ipython serwer pewno ma czasu na pisanie przed I zamknąć gniazdo) ...
import socket
client = socket.create_connection(('localhost', 8888))
client.sendall('echo\n'.encode())
client.close()
... otrzymuję traceback błędu z serwera:
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
problem musi być w jakiś sposób w związku z writer.write
, ponieważ gdy zgłoszę następujący kod klienta (co sprawia, że serwer pominąć pisanie), nie ma błędu:
import socket
client = socket.create_connection(('localhost', 8888))
client.sendall('foo\n'.encode())
client.close()
Odpowiedni dziennik serwera:
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.
Czego mi brakuje? Czy używam asyncio niepoprawnie?
Dzięki!
Wątpię, czy tak jest w tym przypadku. Przykład mojego klienta może być trochę mylący. W rzeczywistości cały kod klienta został ręcznie wprowadzony do sesji IPython (będę edytować to w pytaniu). Powinien więc wystarczyć czas, aby serwer zapisał, zanim klient zostanie zamknięty. Ponadto, jeśli przyjrzymy się dokładnie ścieżce zwrotnej, błąd serwera pojawi się w "readline". – gnargnagnar
@gnargnagnar Spróbuj; błąd zniknie, jeśli "recv" dane zapisane przez serwer. Błąd występuje, jeśli dane są zapisane w gnieździe, które nie zostały faktycznie odebrane przez partnera w czasie zamykania połączenia - tak więc nawet jeśli operacja 'write' została zakończona, jeśli partner zamknie połączenie bez odczytu tych danych , strona lokalna otrzyma błąd, niezależnie od tego, jaka operacja gniazda działa w momencie zamknięcia. Zgadzam się, że moja pierwotna odpowiedź nie wyjaśniła tego. Będę to edytować. – dano
Tak, masz rację. Jeśli wycofam echo z klientem przed zamknięciem, nie otrzymam błędu serwera. Czy istnieje jakikolwiek powód, dla którego serwer dba o to, czy klient odczytał wszystkie dane? Może mam złe postrzeganie gniazd. – gnargnagnar