Python: что произойдет, если скрипт остановится во время выполнения request.get()?

Я знаю, что requests.get() предоставляет HTTP-интерфейс, чтобы программист мог выполнять различные запросы на HTTP-сервер.

Это говорит мне, что где-то должен быть открыт порт, чтобы запрос мог случиться.

Принимая это во внимание, что произойдет, если сценарий будет остановлен (например, прерыванием клавиатуры, поэтому машина, выполняющая сценарий, остается подключенной к Интернету) до того, как ответ будет отвечать/завершен?

Будет ли порт/соединение оставаться открытым?

Закрывается ли порт/соединение автоматически?

Ответ 1

Короткий ответ на вопрос: запросы будут закрывать соединение в случае любого исключения, включая KeyboardInterrupt и SystemExit.

Немного рытья в запросах исходного кода показывает, что requests.get в конечном счете вызывает HTTPAdapter.send метод (который является, где все происходит волшебство).

Есть два способа, с помощью которых запрос мог быть сделан в методе send: chunked или not chunked. Которая 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. В этом случае запросы все еще обрабатывают исключение, он делает это с помощью блока 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. В случае успешного выполнения соединение возвращается в пул соединений (хотя я не могу найти вызов _put_conn в источнике requests для send, что может быть ошибкой в рабочем потоке).

Ответ 2

На гораздо более низком уровне, когда программа выходит, ядро ОС закрывает все дескрипторы файлов, открытые этой программой. К ним относятся сетевые сокеты.