私はasyncioクライアントを使用して接続し、サーバーから切断します。非同期クライアント: `connection_lost`が呼び出されず、ResourceWarningが発生します
同じコンピュータ上のサーバープログラムに接続すると、接続が正常に終了します。追加:接続にデータを書き始めると、この接続でも警告が表示され始めた時には。下記の第2版のバージョンを参照してください。
ローカルネットワーク上のデバイスに接続すると、閉鎖されていないトランスポート用に
ResourceWarning
が得られます。
接続を正しく閉じるにはどうすればよいですか?
私はWindows 7(64ビット)でPython 3.6.0(32ビット)を使用しています。
最初の試み
関連するコード:
import asyncio
import logging
import warnings
class ClientConnection(asyncio.Protocol):
def connection_made(self, transport):
self.transport = transport
transport.write_eof() # Send EOF to close connection
def connection_lost(self, exception):
self.transport.close()
super().connection_lost(exception)
def main():
logging.basicConfig(level=logging.DEBUG)
eventLoop = asyncio.get_event_loop()
eventLoop.set_debug(True)
warnings.simplefilter('always', ResourceWarning) # enables ResourceWarning
#co = eventLoop.create_connection(ClientConnection, '127.0.0.1', 7001) # Works without warning
co = eventLoop.create_connection(ClientConnection, '192.168.10.66', 7001) # Gives warning
try:
eventLoop.run_until_complete(co)
finally:
eventLoop.close()
if __name__ == "__main__":
main()
コンソール出力:
DEBUG:asyncio:Using selector: SelectSelector
DEBUG:asyncio:connect <socket.socket fd=240, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=6> to ('19
2.168.10.66', 7001)
DEBUG:asyncio:poll took 0.000 ms: 1 events
DEBUG:asyncio:<socket.socket fd=240, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=6, laddr=('192.168
.10.62', 64587), raddr=('192.168.10.66', 7001)> connected to 192.168.10.66:7001: (<_SelectorSocketTransport fd=240 read=
polling write=<idle, bufsize=0>>, <__main__.ClientConnection object at 0x005EBD90>)
DEBUG:asyncio:Close <_WindowsSelectorEventLoop running=False closed=False debug=True>
sys:1: ResourceWarning: unclosed <socket.socket fd=240, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto
=6, laddr=('192.168.10.62', 64587), raddr=('192.168.10.66', 7001)>
C:\Program Files (x86)\Python36-32\lib\asyncio\selector_events.py:631: ResourceWarning: unclosed transport <_SelectorSoc
ketTransport fd=240>
source=self)
第二の試み
私は、コードに変更を次のようでした:
connection_lost
- から
transport.close()
を削除し、接続 - 追加
data_received
とeof_received
コールバック - さらに追加のデバッグログ
観察にいくつかのデータを書き込みます。
- 私は
connection_made
にtransport.close()
を追加してみましたしかし、それは常にresulされますtはOSError: [WinError 10038]
です。 注:これは恐らく別の問題ですので、今はこれを無視して、私がこれをしないと仮定しましょう。 - ソケットにデータを書き込むときに、ローカルホスト接続も警告を出すようになりましたが、必ずしもそうとは限りません。
- 警告を発すると、
connection_lost
は呼び出されません。どうして?それが成功したときにimport asyncio import logging import warnings class ClientConnection(asyncio.Protocol): def connection_made(self, transport): logging.debug('connection_made') self.transport = transport transport.write(b'1234\r') transport.write_eof() # Send EOF to close connection #transport.close() # Cannot close here either, gives 'OSError: [WinError 10038]' def connection_lost(self, exception): logging.debug('connection_lost') super().connection_lost(exception) def data_received(self, data): logging.debug('received {} bytes'.format(len(data))) def eof_received(self): logging.debug('EOF received') self.transport.close() def main(): logging.basicConfig(level=logging.DEBUG) eventLoop = asyncio.get_event_loop() eventLoop.set_debug(True) warnings.simplefilter('always', ResourceWarning) # enables ResourceWarning #co = eventLoop.create_connection(ClientConnection, '127.0.0.1', 7001) # Works without warning co = eventLoop.create_connection(ClientConnection, '192.168.10.66', 7001) # Gives warning try: eventLoop.run_until_complete(co) logging.debug('done') finally: eventLoop.close() if __name__ == "__main__": main()
出力::それは失敗し
... DEBUG:root:EOF received DEBUG:root:connection_lost DEBUG:root:done DEBUG:asyncio:Close <_WindowsSelectorEventLoop running=False closed=False debug=True>
出力(
connection_lost
の欠如に注意してください):コード修正
...
DEBUG:root:EOF received
DEBUG:root:done
DEBUG:asyncio:Close <_WindowsSelectorEventLoop running=False closed=False debug=True>
sys:1: ResourceWarning: unclosed <socket.socket fd=240, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto
=6, laddr=('127.0.0.1', 63858), raddr=('127.0.0.1', 7001)>
C:\Program Files (x86)\Python36-32\lib\asyncio\selector_events.py:631: ResourceWarning: unclosed transport <_SelectorSoc
ketTransport closing fd=240>
source=self)
)は(transport.close :-) Linux上で 'WinError'を再現することはできません正常に動作します:ここでは、ローカルとリモートマシン上echo server秒を想定し
loop.run_forever()
とloop.stop()
を、使用した例があります。 '.close()'の前に 'time.sleep(0.05)'を追加してみてください。 – Udi@Udiタイムアウトは役に立たないようですが、Windowsは何かについて気になるようです。私はおそらくそれについて別の質問をするでしょう。 *しかし、遅延だけを使用すると元の問題を防ぐことができます。私はいくつかのテストをする必要がありますが、私のプログラムではすべてが速すぎるかもしれません。これまでのご協力ありがとうございます。 – user694733
明らかに、ウィンドウ 'write_eof'は' close() 'を呼び出します。また、ループを永遠に実行し、 'connection_lost'で' stop() 'を実行してみてください。 – Udi