我知道它requests.get()
提供了一个 HTTP 接口,以便程序员可以向 HTTP 服务器发出各种请求。
这告诉我必须在某个地方打开一个端口才能发生请求。
考虑到这一点,如果脚本在请求被回答/完成之前停止(例如,通过键盘中断,因此正在执行脚本的机器仍然连接到互联网)会发生什么?
端口/连接会保持打开状态吗?
端口/连接会自动关闭吗?
我知道它requests.get()
提供了一个 HTTP 接口,以便程序员可以向 HTTP 服务器发出各种请求。
这告诉我必须在某个地方打开一个端口才能发生请求。
考虑到这一点,如果脚本在请求被回答/完成之前停止(例如,通过键盘中断,因此正在执行脚本的机器仍然连接到互联网)会发生什么?
端口/连接会保持打开状态吗?
端口/连接会自动关闭吗?
对这个问题的简短回答是:请求将在出现任何异常的情况下关闭连接,包括KeyboardInterrupt
and SystemExit
。
稍微 深入研究一下 requests 的源代码,就会发现requests.get
最终调用了该HTTPAdapter.send
方法(这是所有魔法发生的地方)。
在方法中可以通过两种方式发出请求send
:分块或不分块。我们send
执行的操作取决于request.body
和Content-Length
标头的值:
chunked = not (request.body is None or 'Content-Length' in request.headers)
在请求主体为None
或Content-Length
设置的情况下,requests
将使用以下高级urlopen
方法urllib3
:
if not chunked:
resp = conn.urlopen(
method=request.method,
url=url,
body=request.body,
# ...
)
该方法的finally
块具有处理在块未成功执行urllib3.PoolManager.urlopen
的情况下关闭连接的代码:try
clean_exit = False
# ...
try:
# ...
# Everything went great!
clean_exit = True
finally:
if not clean_exit:
# We hit some kind of exception, handled or otherwise. We need
# to throw the connection away unless explicitly told not to.
# Close the connection, set the variable to None, and make sure
# we put the None back in the pool to avoid leaking it.
conn = conn and conn.close()
release_this_conn = True
在响应可以被分块的情况下,请求会稍微低一些,并使用由urllib3
. 在这种情况下,requests 仍然处理异常,它使用try
/except
块执行此操作,该块在获取连接后立即开始,并以以下方式结束:
low_conn = conn._get_conn(timeout=DEFAULT_POOL_TIMEOUT)
try:
# ...
except:
# If we hit any problems here, clean up the connection.
# Then, reraise so that we can handle the actual exception.
low_conn.close()
raise
有趣的是,如果没有错误,连接可能不会urllib3
关闭,具体取决于您如何为. 在成功执行的情况下,连接被放回连接池(尽管我在源中找不到 chunked 的_put_conn
调用,这可能是分块工作流程中的错误)。requests
send
在低得多的级别上,当程序退出时,操作系统内核会关闭该程序打开的所有文件描述符。这些包括网络套接字。