I am using asyncio client to connect and then disconnect from server.
If I connect to server program on the same computer, connection closes fine. Add: When I started writing data to connection, this connection also started giving warnings sometimes. See second code version below.
If I connect to device on the local network, I get ResourceWarning
for unclosed transport.
How do I close the connection correctly?
I am using Python 3.6.0 (32-bit) on Windows 7 (64-bit).
Relevant code:
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()
Console output:
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)
I did following changes to the code:
transport.close()
from connection_lost
data_received
and eof_received
callbacksObservations:
transport.close()
to connection_made
, but it will always result in OSError: [WinError 10038]
. Note: This probably another problem, so let's ignore this for now, and assume I won't do this.connection_lost
is not called. Why?Modified code:
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()
Output when it succeeds:
...
DEBUG:root:EOF received
DEBUG:root:connection_lost
DEBUG:root:done
DEBUG:asyncio:Close <_WindowsSelectorEventLoop running=False closed=False debug=True>
Output when it fails (note the lack of 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)
Try running the loop a little more. Here is an example using loop.run_forever()
and loop.stop()
, assuming echo servers on local and remote machines:
import asyncio
import logging
import warnings
class ClientConnection(asyncio.Protocol):
def connection_made(self, transport):
logging.debug("connection made, sending and calling write eof")
transport.write(b'hello')
transport.write_eof()
logging.debug("after calling write eof")
def data_received(self, data):
logging.debug("Got: {}".format(data))
super().data_received(data)
def connection_lost(self, exception):
logging.debug("connection lost")
super().connection_lost(exception)
loop.stop()
def test_echo(ip, port):
logging.debug("Creating connection: {}:{}".format(ip, port))
co = loop.create_connection(ClientConnection, ip, port)
logging.debug("Starting loop...")
print(loop.run_until_complete(co))
logging.debug("...create_connection done, running loop forever...")
loop.run_forever()
logging.debug("Loop stopped")
logging.debug('----------------')
if __name__ == "__main__":
logging.basicConfig(level=logging.DEBUG)
warnings.simplefilter('always') # enables ResourceWarning
loop = asyncio.get_event_loop()
loop.set_debug(True)
test_echo('127.0.0.1', 7001)
test_echo('54.175.103.105', 30000)
logging.debug("done")
loop.close()
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With