Что происходит при вводе URL в браузере?

«Что происходит при вводе URL в браузере?» — вопрос из категории Сети, который задают на 25% собеседований C/C++ Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Это многоэтапный процесс, начиная с сетевого уровня и заканчивая рендерингом. С точки зрения программиста на C++, понимание этих этапов критично для написания сетевого кода, отладки и оптимизации.

Основные этапы:

  1. DNS-резолвинг: Браузер извлекает доменное имя (например, example.com) из URL и преобразует его в IP-адрес. Это может включать проверку кешей (браузера, ОС, роутера) и рекурсивные запросы к DNS-серверам.
  2. Установка TCP-соединения (3-way handshake):
    • Клиент (браузер) отправляет пакет с флагом SYN (synchronize).
    • Сервер отвечает пакетом SYN-ACK (synchronize-acknowledge).
    • Клиент отправляет ACK (acknowledge). Соединение установлено.
  3. TLS handshake (для HTTPS): Если используется HTTPS, происходит обмен ключами и согласование параметров шифрования (например, с использованием протокола TLS 1.3).
  4. Отправка HTTP-запроса: Браузер формирует и отправляет HTTP-запрос (например, GET /index.html HTTP/1.1) через установленное соединение.
  5. Получение и обработка ответа: Сервер отправляет HTTP-ответ (статус, заголовки, тело). Браузер начинает парсить полученный HTML.
  6. Загрузка ресурсов и рендеринг: На основе HTML браузер запрашивает связанные ресурсы (CSS, JS, изображения), строит DOM, CSSOM, рендеринг-дерево и отрисовывает страницу.

Упрощенный пример на C++ (сырые сокеты, без обработки ошибок):

#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <iostream>
#include <cstring>

void fetchPage(const char* host, const char* path) {
    // 1. Создание сокета (пока без DNS, используем прямой IP для примера)
    int sock = socket(AF_INET, SOCK_STREAM, 0);

    // 2. Установка адреса сервера и подключение (этап TCP handshake)
    struct sockaddr_in server_addr{};
    server_addr.sin_family = AF_INET;
    server_addr.sin_port = htons(80); // HTTP порт
    inet_pton(AF_INET, "93.184.216.34", &server_addr.sin_addr); // IP example.com

    connect(sock, (struct sockaddr*)&server_addr, sizeof(server_addr));

    // 3. Формирование и отправка HTTP GET-запроса
    std::string request = "GET " + std::string(path) + " HTTP/1.1rn" +
                          "Host: " + std::string(host) + "rn" +
                          "Connection: closernrn";
    send(sock, request.c_str(), request.size(), 0);

    // 4. Чтение ответа
    char buffer[4096];
    ssize_t bytes_read;
    while ((bytes_read = recv(sock, buffer, sizeof(buffer) - 1, 0)) > 0) {
        buffer[bytes_read] = '';
        std::cout << buffer; // Вывод сырого HTTP-ответа
    }

    // 5. Закрытие сокета
    close(sock);
}

// На практике используют библиотеки вроде libcurl, Boost.Beast или ASIO.