← Назад к вопросам

Какая сущность создается при отправке сетевых запросов в ОС?

2.0 Middle🔥 171 комментариев
#Базы данных (SQL)

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Сущность при отправке сетевых запросов: Socket

Ответ: при отправке сетевого запроса операционная система создаёт сокет (socket) — это конечная точка сетевого соединения.

Что такое сокет?

Сокет — это абстрактный интерфейс, через который приложение взаимодействует с сетевым стеком ОС. Можешь думать о сокете как о "электрической розетке" для сетей: ты подключаешь свой код, и через розетку идёт передача данных.

┌─────────────────────────────────────┐
│   Приложение (Python код)          │
└───────────────┬─────────────────────┘
                │
          Создаёт сокет
                │
┌───────────────▼─────────────────────┐
│      ОС (Kernel)                   │
│  ┌─────────────────────────────┐   │
│  │   Socket Descriptor (FD)    │   │
│  │  (File descriptor)          │   │
│  │                             │   │
│  │  - Protocol (TCP/UDP)       │   │
│  │  - Local IP:Port            │   │
│  │  - Remote IP:Port           │   │
│  │  - Send buffer              │   │
│  │  - Receive buffer           │   │
│  └─────────────────────────────┘   │
└───────────────┬─────────────────────┘
                │
        Сетевой интерфейс
                │
          ┌─────▼──────┐
          │ Ethernet   │
          │ Wi-Fi      │
          │ 4G/5G      │
          └────────────┘

Типы сокетов

TCP сокет (SOCK_STREAM)

import socket

# Создание TCP сокета
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

# Соединение с сервером
sock.connect(('google.com', 80))

# Отправка данных
sock.sendall(b'GET / HTTP/1.1\r\nHost: google.com\r\n\r\n')

# Получение ответа
data = sock.recv(4096)

# Закрытие сокета
sock.close()

Особенности TCP:

  • Надёжный — гарантирует доставку в порядке
  • Ориентирован на соединение — нужна установка соединения (handshake)
  • Медленнее чем UDP из-за проверок

UDP сокет (SOCK_DGRAM)

import socket

# Создание UDP сокета
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

# Отправка датаграммы (без соединения!)
sock.sendto(b'Hello', ('192.168.1.1', 5005))

# Получение датаграммы
data, addr = sock.recvfrom(1024)

# Закрытие
sock.close()

Особенности UDP:

  • Ненадёжный — может потеряться пакет
  • Без соединения — отправляешь сразу, без handshake
  • Быстрее чем TCP
  • Используется для: VoIP, онлайн игры, DNS запросы

Что создаёт ОС при создании сокета?

1. File Descriptor (дескриптор файла)

ОС назначает целое число — file descriptor (FD):

import socket

sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
print(sock.fileno())  # Вывод: 3 (или 4, или 5, etc.)

Зачем? ОС работает со всем через файлы: "всё в Unix это файл". Сокет — это тоже файл (специальный).

2. Буфферы отправки и получения (buffers)

ОС создаёт:
┌────────────────────┐
│ Send Buffer (TX)   │  Очередь для отправки
│ (64KB по дефолту)  │  write() → сюда
└────────────────────┘

┌────────────────────┐
│ Recv Buffer (RX)   │  Очередь для приёма
│ (64KB по дефолту)  │  read() → отсюда
└────────────────────┘

3. TCP Connection State Machine

Для TCP сокета ОС отслеживает состояние:
CLOSED
  ↓ (connect)
SYN_SENT
  ↓ (SYN+ACK received)
ESTABLISHED
  ↓ (close)
FIN_WAIT_1
  ↓
FIN_WAIT_2
  ↓
TIME_WAIT (30-120 сек)
  ↓
CLOSED

Практический пример: как работает запрос

import socket
import time

# Шаг 1: Создание сокета
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# ОС создаёт: FD=3, buffers, инициализирует state=CLOSED

# Шаг 2: Соединение (только для TCP!)
sock.connect(('example.com', 80))
# ОС отправляет SYN пакет, ждёт SYN+ACK, state=ESTABLISHED

# Шаг 3: Отправка данных
request = b'GET / HTTP/1.1\r\nHost: example.com\r\n\r\n'
sock.sendall(request)
# ОС кладёт данные в send buffer, отправляет по сети

# Шаг 4: Получение ответа
response = b''
while True:
    try:
        chunk = sock.recv(4096)  # Читает из recv buffer
        if not chunk:
            break
        response += chunk
    except socket.timeout:
        break

# Шаг 5: Закрытие сокета
sock.close()
# ОС отправляет FIN пакет, ждёт FIN+ACK, state=TIME_WAIT -> CLOSED

Лимиты и проблемы

Проблема 1: утечка сокетов

# Плохо — сокеты не закрыты
for i in range(10000):
    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    sock.connect(('example.com', 80))
    # Забыл close!

# ОС быстро исчерпает лимит открытых файлов (~1024 по дефолту)
# OSError: [Errno 24] Too many open files

Хорошо — используй контекст-менеджер

import socket

for i in range(10000):
    with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock:
        sock.connect(('example.com', 80))
        # Автоматически close() при выходе

Проблема 2: TIME_WAIT очередь

А часто закрываемые сокеты создают TIME_WAIT:ы:

netstat -an | grep TIME_WAIT | wc -l
# Вывод: 5432 сокетов в TIME_WAIT!

Решение: включи SO_REUSEADDR:

sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sock.bind(('0.0.0.0', 8080))

На собеседовании

"При отправке сетевого запроса ОС создаёт сокет — это file descriptor с буфферами отправки/получения и таблицей состояния (для TCP). Сокет — это абстракция, через которую приложение взаимодействует с сетевым стеком. Важно закрывать сокеты, иначе получишь утечку."

Это показывает понимание низкоуровневых механик.

Какая сущность создается при отправке сетевых запросов в ОС? | PrepBro