gpt4 book ai didi

python - 异步客户端 : `connection_lost` not called, 导致 ResourceWarning

转载 作者:太空宇宙 更新时间:2023-11-04 02:58:25 29 4
gpt4 key购买 nike

我正在使用 asyncio 客户端连接服务器,然后断开连接。

  • 如果我连接到同一台计算机上的服务器程序,连接正常关闭。 添加:当我开始向连接写入数据时,此连接也开始提供警告有时。请参阅下面的第二个代码版本。

  • 如果我连接到本地网络上的设备,我会收到未封闭传输的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_receivedeof_received 回调
  • 添加了更多调试日志

观察:

  • 我尝试将 transport.close() 添加到 connection_made,但它总是会导致 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() 关闭传输。这也会触发 connection_lost(不要从 connection_lost 调用 transport.close()!):

class ClientConnection(asyncio.Protocol):
def connection_made(self, transport):
logging.debug("connection made, calling write eof")
transport.write_eof()
logging.debug("after calling write eof, calling close")
transport.close()
logging.debug("after calling close")

def connection_lost(self, exception):
logging.debug("connection lost")
super().connection_lost(exception)

如果您多尝试一些,您可能还会为您的本地计算机收到一些 ResourceWarning。例如,尝试在 write_eof() 之前添加 transport.write(b'hello world!') 或使本地服务器响应速度变慢。

关于python - 异步客户端 : `connection_lost` not called, 导致 ResourceWarning,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41695498/

29 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com