Сокет в компьютерных сетях¶
Сокет (англ. socket, «гнездо», «разъём») — программный интерфейс (API) для организации межпроцессного и сетевого взаимодействия, а также абстракция конечной точки двунаправленного канала связи между процессами. В операционных системах семейства UNIX и Linux сокет представляет собой файловый дескриптор, через который программа может читать и записывать данные, передаваемые по сети или между процессами на одном компьютере. Понятие было введено в 1983 году в системе 4.2BSD и с тех пор стало стандартом для сетевого программирования на платформах UNIX, Linux, Windows и других.
¶История
Сокеты появились в системе 4.2BSD, разработанной в Калифорнийском университете в Беркли. До этого сетевые программы использовали более низкоуровневые интерфейсы, привязанные к конкретным протоколам. Идея сокетов заключалась в создании единого абстрактного механизма, позволяющего работать с разными протоколами (TCP, UDP, IPX и др.) через одинаковый набор системных вызовов. Позднее сокетный API был стандартизирован в стандарте POSIX и стал частью спецификации IEEE Std 1003.1 (POSIX.1). В Windows аналогичный интерфейс реализован в виде библиотеки Winsock.
¶Классификация
Сокеты классифицируются по нескольким признакам.
По домену (семейству адресов):
- AF_INET — IPv4, наиболее распространённый вариант;
- AF_INET6 — IPv6;
- AF_UNIX (AF_LOCAL) — межпроцессное взаимодействие на одном компьютере через файловую систему;
- AF_NETLINK — общение с ядром Linux;
- AF_PACKET — работа на уровне сетевых кадров.
По типу:
- SOCK_STREAM — потоковые сокеты, работающие поверх TCP (или протокола UNIX-сокетов). Обеспечивают надёжную доставку, порядок и контроль потока.
- SOCK_DGRAM — датаграммные сокеты поверх UDP. Не гарантируют доставку и порядок пакетов, но работают быстрее.
- SOCK_RAW — «сырые» сокеты, предоставляющие доступ к пакетам нижележащего уровня (требуют повышенных привилегий).
- SOCK_SEQPACKET — последовательные датаграммные сокеты с сохранением границ сообщений.
¶Устройство и принцип работы
Работа с сокетами строится на последовательности системных вызовов. Серверная сторона выполняет следующие шаги:
socket()— создание сокета с указанием домена, типа и протокола.bind()— привязка сокета к локальному адресу и порту.listen()— переход в режим прослушивания входящих соединений (для потоковых сокетов).accept()— принятие входящего соединения, в результате которого создаётся новый сокет для общения с конкретным клиентом.read()/write()(илиrecv()/send()) — приём и передача данных.close()— закрытие сокета.
Клиентская сторона обычно выполняет socket(), затем connect() для установления соединения с сервером, после чего читает и пишет данные и закрывает сокет.
Для датаграммных сокетов вызовы listen() и accept() не используются: вместо них применяются sendto() и recvfrom(), позволяющие указывать адрес получателя при каждой отправке.
¶Мультиплексирование
Когда процессу нужно обслуживать несколько соединений одновременно, применяется мультиплексирование. В Linux и UNIX доступны механизмы select(), poll() и epoll(), в Windows — select() и комплект ввода-вывода (IOCP). Эти механизмы позволяют одним потоком отслеживать готовность нескольких сокетов к чтению или записи, что лежит в основе большинства высокопроизводительных сетевых серверов.
¶Применение
Сокеты являются основой большинства сетевых протоколов и приложений:
- веб-серверы и клиенты (HTTP/HTTPS поверх TCP-сокетов);
- почтовые системы (SMTP, POP3, IMAP);
- системы доменных имён (DNS);
- удалённое управление (SSH, RDP);
- стриминг медиа;
- протоколы мгновенных сообщений;
- клиент-серверные и многопользовательские игры.
Межпроцессное взаимодействие через UNIX-сокеты широко используется в Linux-системах: например, systemd, X Window System и многие демонсы общаются именно через них.
¶Сокеты в разных языках программирования
В языке C сокетный API предоставляется библиотекой libc. В Python работа с сокетами реализована в модуле socket стандартной библиотеки. В Java используется класс java.net.Socket и java.nio.channels.ServerSocketChannel. В Go стандартный пакет net предоставляет высокоуровневую обёртку над сокетами. В Node.js сокеты доступны через модуль net и dgram.
¶Интересные факты
- В Linux сокеты реализованы как файловые дескрипторы, поэтому их можно передавать между процессами через механизм передачи файловых дескрипторов (SCM_RIGHTS).
- Понятие «сокет» иногда используется в разговорной речи программистов для обозначения IP-адреса в паре с номером порта, например «127.0.0.1:8080».
- UNIX-сокеты работают быстрее TCP-сокетов на localhost, так как не проходят полный сетевой стек.
Источники:
- «UNIX Network Programming, Volume 1: Networking APIs» — W. Richard Stevens
- «The Linux Programming Interface» — Michael Kerrisk
- POSIX.1-2017 (IEEE Std 1003.1)
- Документация Linux man-pages: socket(2), bind(2), listen(2), accept(2)
- RFC 793 (Transmission Control Protocol)
