RuntimeError: File descriptor 8 is used by transport

ⅰ亾dé卋堺 提交于 2021-02-10 17:52:27

问题


Minimal demonstration example:

import asyncio

async def main():
    c1_reader, c1_writer = await asyncio.open_connection(host='google.com', port=80)
    c1_socket = c1_writer.get_extra_info('socket')
    c1_socket.close()

    c2_reader, c2_writer = await asyncio.open_connection(host='google.com', port=80)

asyncio.run(main())

Running this program gives this error:

$ python3 asyncio_fd_used.py
Traceback (most recent call last):
  File "/opt/local/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/asyncio/selector_events.py", line 469, in _sock_connect
    sock.connect(address)
BlockingIOError: [Errno 36] Operation now in progress

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "asyncio_fd_used.py", line 11, in <module>
    asyncio.run(main())
  File "/opt/local/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/asyncio/runners.py", line 43, in run
    return loop.run_until_complete(main)
  File "/opt/local/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/asyncio/base_events.py", line 579, in run_until_complete
    return future.result()
  File "asyncio_fd_used.py", line 9, in main
    c2_reader, c2_writer = await asyncio.open_connection(host='google.com', port=80)
  File "/opt/local/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/asyncio/streams.py", line 77, in open_connection
    lambda: protocol, host, port, **kwds)
  File "/opt/local/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/asyncio/base_events.py", line 941, in create_connection
    await self.sock_connect(sock, address)
  File "/opt/local/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/asyncio/selector_events.py", line 463, in sock_connect
    self._sock_connect(fut, sock, address)
  File "/opt/local/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/asyncio/selector_events.py", line 477, in _sock_connect
    self.add_writer(fd, self._sock_connect_cb, fut, sock, address)
  File "/opt/local/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/asyncio/selector_events.py", line 333, in add_writer
    self._ensure_fd_no_transport(fd)
  File "/opt/local/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/asyncio/selector_events.py", line 244, in _ensure_fd_no_transport
    f'File descriptor {fd!r} is used by transport '
RuntimeError: File descriptor 8 is used by transport <_SelectorSocketTransport fd=8 read=polling write=<idle, bufsize=0>>

Just for explanation why I am doing the low-level socket.close() and not asyncio-level writer.close(): I was trying some code to send RST packet. But I can imagine other reasons why people would call socket.close(), maybe even unintentionally.


回答1:


The problem is that the low-level socket is closed, but asyncio doesn't know about that and thinks it is still open. For some reason (performance?) asyncio remembers the socket file descriptor (fileno).

When a new connection is opened, operating system gives to it the same file descriptor number, and asyncio starts panicking, because it has the same exact fd number associated with that previous connection.

Solution: tell asyncio the socket is closed :)

import asyncio

async def main():
    c1_reader, c1_writer = await asyncio.open_connection(host='google.com', port=80)
    c1_socket = c1_writer.get_extra_info('socket')
    c1_socket.close()
    c1_writer.close()  # <<< here

    c2_reader, c2_writer = await asyncio.open_connection(host='google.com', port=80)

asyncio.run(main())

This code runs without raising an error.



来源:https://stackoverflow.com/questions/57200946/runtimeerror-file-descriptor-8-is-used-by-transport

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!