Ich bin neu in Python 3 und spiele mit asyncio herum. Dabei erlebe ich ein seltsames Verhalten mit dem folgenden serverseitigen Code:Warum erhalte ich hier einen 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()
Wenn ich diesen Client Code ausführen (EDIT: Client-Code wird manuell in eine IPython Sitzung eingegeben, der Server hat auf jeden Fall Zeit zu schreiben, bevor ich schließe die Buchse) ...
import socket
client = socket.create_connection(('localhost', 8888))
client.sendall('echo\n'.encode())
client.close()
... ich erhalte eine Fehlerrückverfolgung von dem 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
die Frage muss irgendwie in Beziehung mit writer.write
, weil, wenn ich den folgenden Client-Code aufrufen (die der Server überspringen das Schreiben macht), kein Fehler vorhanden ist:
import socket
client = socket.create_connection(('localhost', 8888))
client.sendall('foo\n'.encode())
client.close()
Der entsprechende 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.
Was bin ich? Verwende ich Asyncio falsch?
Danke!
Ich bezweifle, dass dies der Fall ist. Mein Client-Beispiel kann ein bisschen irreführend sein. In der Tat wurde der gesamte Client-Code manuell in eine IPython-Sitzung eingegeben (ich werde dies in der Frage bearbeiten). Daher sollte genügend Zeit für den Server vorhanden sein, um zu schreiben, bevor der Client geschlossen wird. Wenn Sie sich das Traceback genauer ansehen, tritt der Serverfehler bei "readline" auf. – gnargnagnar
@gnargnagnar Probieren Sie es aus; Der Fehler verschwindet, wenn Sie die vom Server geschriebenen Daten abrufen. Der Fehler tritt auf, wenn Daten in den Socket geschrieben werden, die zum Zeitpunkt des Verbindungsabbruchs vom Peer nicht tatsächlich empfangen wurden - also auch dann, wenn die 'write'-Operation abgeschlossen ist, wenn der Peer die Verbindung schließt, ohne diese Daten zu lesen , die lokale Seite erhält einen Fehler bei der Socket-Operation, die gerade ausgeführt wird, wenn sie geschlossen ist. Ich stimme zu, dass meine ursprüngliche Antwort dies jedoch nicht klarstellte. Ich werde es bearbeiten. – dano
Ja, Sie haben Recht. Wenn ich das Echo vor dem Schließen mit dem Client einlese, erhalte ich den Serverfehler nicht. Gibt es einen Grund, warum der Server sich darum kümmert, ob der Client dann alle Daten ausgelesen hat? Vielleicht habe ich eine falsche Vorstellung von Steckdosen .. – gnargnagnar