Как соотносятся уровни модели OSI и как они реализуются в сетевом программировании на C++?

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

Ответ

Модель OSI (Open Systems Interconnection) — это теоретическая 7-уровневая модель, описывающая, как данные передаются по сети. На практике стек TCP/IP (4 уровня) является ее реализацией. Уровни соотносятся по принципу инкапсуляции: данные с верхнего уровня становятся полезной нагрузкой (payload) для протокола нижнего уровня, который добавляет свой заголовок.

Соответствие уровней OSI и TCP/IP: Уровень OSI Уровень TCP/IP Пример протоколов Задача Пример в C++ (сокеты)
7. Прикладной Прикладной HTTP, FTP, SMTP, DNS Интерфейс для приложений Библиотеки: cURL, gRPC, Boost.Asio для HTTP
6. Представления (Включен в Прикладной) SSL/TLS, JSON/XML parsers Шифрование, сжатие, кодирование OpenSSL для TLS, библиотеки сериализации
5. Сеансовый (Включен в Прикладной) SOCKS, RPC Управление сеансом связи Состояние соединения в клиент-серверном приложении
4. Транспортный Транспортный TCP, UDP Надежная/ненадежная доставка данных между процессами Создание сокета: socket(AF_INET, SOCK_STREAM, 0) (TCP)
3. Сетевой Интернет IP (IPv4/IPv6), ICMP Маршрутизация пакетов по сети Заполнение структуры sockaddr_in (IP-адрес, порт)
2. Канальный Сетевой интерфейс Ethernet (MAC), Wi-Fi (802.11) Передача кадров между соседними узлами Обычно управляется ОС и драйверами
1. Физический (Аппаратный) Витая пара, оптоволокно Передача битов Не программируется на уровне C++

Практический пример на C++ (сырые сокеты Беркли):

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

int main() {
    // Уровень 4 (Транспортный): Создаем TCP-сокет (SOCK_STREAM)
    int server_fd = socket(AF_INET, SOCK_STREAM, 0);

    // Уровень 3 (Сетевой): Настраиваем адрес (IP и порт)
    struct sockaddr_in address;
    address.sin_family = AF_INET;          // Семейство адресов IPv4
    address.sin_addr.s_addr = INADDR_ANY;  // Принимать соединения на все интерфейсы
    address.sin_port = htons(8080);        // Порт 8080 (преобразование в сетевой порядок байт)

    // Связываем сокет с адресом (уровни 3 и 4)
    bind(server_fd, (struct sockaddr*)&address, sizeof(address));

    // Начинаем прослушивание (уровень 5, управление сеансом)
    listen(server_fd, 3);
    std::cout << "Server listening on port 8080..." << std::endl;

    // Принимаем соединение
    int addrlen = sizeof(address);
    int new_socket = accept(server_fd, (struct sockaddr*)&address, (socklen_t*)&addrlen);

    // Уровень 7 (Прикладной): Читаем и отправляем данные (простой HTTP-ответ)
    const char* response = 
        "HTTP/1.1 200 OKrn"
        "Content-Type: text/plainrn"
        "Content-Length: 13rn"
        "rn"
        "Hello, OSI!n";
    send(new_socket, response, strlen(response), 0);

    close(new_socket);
    close(server_fd);
    return 0;
}

Современный подход на C++: Использование высокоуровневых библиотек, таких как Boost.Asio, которые абстрагируют низкоуровневые детали сокетов и предоставляют асинхронный ввод-вывод, упрощая работу с транспортным и сетевым уровнями.