15

我知道它requests.get()提供了一个 HTTP 接口,以便程序员可以向 HTTP 服务器发出各种请求。

这告诉我必须在某个地方打开一个端口才能发生请求。

考虑到这一点,如果脚本在请求被回答/完成之前停止(例如,通过键盘中断,因此正在执行脚本的机器仍然连接到互联网)会发生什么?

端口/连接会保持打开状态吗?

端口/连接会自动关闭吗?

4

2 回答 2

12

对这个问题的简短回答是:请求将在出现任何异常的情况下关闭连接,包括KeyboardInterruptand SystemExit

稍微 深入研究一下 requests 的源代码,就会发现requests.get最终调用了该HTTPAdapter.send方法(这是所有魔法发生的地方)。

在方法中可以通过两种方式发出请求send:分块或不分块。我们send执行的操作取决于request.bodyContent-Length标头的值:

chunked = not (request.body is None or 'Content-Length' in request.headers)

在请求主体为NoneContent-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调用,这可能是分块工作流程中的错误)。requestssend

于 2018-08-13T23:38:42.487 回答
1

在低得多的级别上,当程序退出时,操作系统内核会关闭该程序打开的所有文件描述符。这些包括网络套接字。

于 2018-08-20T11:09:06.153 回答