что такое сокет сетевые технологии

Сокеты¶

Сокеты (англ. socket — разъём) — название программного интерфейса для обеспечения обмена данными между процессами. Процессы при таком обмене могут исполняться как на одной ЭВМ, так и на различных ЭВМ, связанных между собой сетью. Сокет — абстрактный объект, представляющий конечную точку соединения.

Принципы сокетов¶

Каждый процесс может создать слушающий сокет (серверный сокет) и привязать его к какому-нибудь порту операционной системы (в UNIX непривилегированные процессы не могут использовать порты меньше 1024). Слушающий процесс обычно находится в цикле ожидания, то есть просыпается при появлении нового соединения. При этом сохраняется возможность проверить наличие соединений на данный момент, установить тайм-аут для операции и т.д.

Каждый сокет имеет свой адрес. ОС семейства UNIX могут поддерживать много типов адресов, но обязательными являются INET-адрес и UNIX-адрес. Если привязать сокет к UNIX-адресу, то будет создан специальный файл (файл сокета) по заданному пути, через который смогут сообщаться любые локальные процессы путём чтения/записи из него (см. Доменный сокет Unix). Сокеты типа INET доступны из сети и требуют выделения номера порта.

Обычно клиент явно подсоединяется к слушателю, после чего любое чтение или запись через его файловый дескриптор будут передавать данные между ним и сервером.

Основные функции¶

Общие
SocketСоздать новый сокет и вернуть файловый дескриптор
SendОтправить данные по сети
ReceiveПолучить данные из сети
CloseЗакрыть соединение
Серверные
BindСвязать сокет с IP-адресом и портом
ListenОбъявить о желании принимать соединения. Слушает порт и ждет когда будет установлено соединение
AcceptПринять запрос на установку соединения
Клиентские
ConnectУстановить соединение

socket()¶

Создаёт конечную точку соединения и возвращает файловый дескриптор. Принимает три аргумента:

domain указывающий семейство протоколов создаваемого сокета

type

protocol

Протоколы обозначаются символьными константами с префиксом IPPROTO_* (например, IPPROTO_TCP или IPPROTO_UDP). Допускается значение protocol=0 (протокол не указан), в этом случае используется значение по умолчанию для данного вида соединений.

Функция возвращает −1 в случае ошибки. Иначе, она возвращает целое число, представляющее присвоенный дескриптор.

Связывает сокет с конкретным адресом. Когда сокет создается при помощи socket(), он ассоциируется с некоторым семейством адресов, но не с конкретным адресом. До того как сокет сможет принять входящие соединения, он должен быть связан с адресом. bind() принимает три аргумента:

Возвращает 0 при успехе и −1 при возникновении ошибки.

Автоматическое получение имени хоста.

listen()¶

Подготавливает привязываемый сокет к принятию входящих соединений. Данная функция применима только к типам сокетов SOCK_STREAM и SOCK_SEQPACKET. Принимает два аргумента:

После принятия соединения оно выводится из очереди. В случае успеха возвращается 0, в случае возникновения ошибки возвращается −1.

accept()¶

Используется для принятия запроса на установление соединения от удаленного хоста. Принимает следующие аргументы:

Функция возвращает дескриптор сокета, связанный с принятым соединением, или −1 в случае возникновения ошибки.

connect()¶

Устанавливает соединение с сервером.

Некоторые типы сокетов работают без установления соединения, это в основном касается UDP-сокетов. Для них соединение приобретает особое значение: цель по умолчанию для посылки и получения данных присваивается переданному адресу, позволяя использовать такие функции как send() и recv() на сокетах без установления соединения.

Загруженный сервер может отвергнуть попытку соединения, поэтому в некоторых видах программ необходимо предусмотреть повторные попытки соединения.

Возвращает целое число, представляющее код ошибки: 0 означает успешное выполнение, а −1 свидетельствует об ошибке.

Передача данных¶

Для передачи данных можно пользоваться стандартными функциями чтения/записи файлов read и write, но есть специальные функции для передачи данных через сокеты:

Нужно обратить внимание, что при использовании протокола TCP (сокеты типа SOCK_STREAM) есть вероятность получить меньше данных, чем было передано, так как ещё не все данные были переданы, поэтому нужно либо дождаться, когда функция recv возвратит 0 байт, либо выставить флаг MSG_WAITALL для функции recv, что заставит её дождаться окончания передачи. Для остальных типов сокетов флаг MSG_WAITALL ничего не меняет (например, в UDP весь пакет = целое сообщение).

Источник

Сокеты в ОС Linux

В данной статье будет рассмотрено понятие сокета в операционной системе Linux: основные структуры данных, как они работают и можно ли управлять состоянием сокета с помощью приложения. В качестве практики будут рассмотрены инструменты netcat и socat.

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

Как видно по исходным кодам, все структуры достаточно объемны. Работа с ними возможна при использовании языка программирования или специальных оберток и написания приложения. Для эффективного управления этими структурами нужно знать, какие типы операций над сокетами существуют и когда их применять. Для сокетов существует набор стандартных действий:

Если о структурах, которые описаны выше, заботится ядро операционной системы, то в случае команд по управлению соединением ответственность берет на себя приложение, которое хочет пересылать данные по сети. Попробуем использовать знания о сокетах для работы с приложениями netcat и socat.

netcat

Оригинальная утилита появилась 25 лет назад, больше не поддерживается. На cегодняшний день существуют порты, которые поддерживаются различными дистрибутивами: Debian, Ubuntu, FreeBSD, MacOS. В операционной системе утилиту можно вызвать с помощью команды nc, nc.traditional или ncat в зависимости от ОС. Утилита позволяет «из коробки» работать с сокетами, которые используют в качестве транспорта TCP и UDP протоколы. Примеры сценариев использования, которые, по мнению автора, наиболее интересны:

перенаправление входящих/исходящих запросов;

трансляция данных на экран в шестнадцатеричном формате.

Опробуем операции в действии. Задача будет состоять в том, что необходимо отправить TCP данные через netcat в UDP соединение. Для лабораторной будет использоваться следующая топология сети:

что такое сокет сетевые технологии. Смотреть фото что такое сокет сетевые технологии. Смотреть картинку что такое сокет сетевые технологии. Картинка про что такое сокет сетевые технологии. Фото что такое сокет сетевые технологии

В итоге получаем возможность читать данные от машины Source:

что такое сокет сетевые технологии. Смотреть фото что такое сокет сетевые технологии. Смотреть картинку что такое сокет сетевые технологии. Картинка про что такое сокет сетевые технологии. Фото что такое сокет сетевые технологии

В машине Destination:

что такое сокет сетевые технологии. Смотреть фото что такое сокет сетевые технологии. Смотреть картинку что такое сокет сетевые технологии. Картинка про что такое сокет сетевые технологии. Фото что такое сокет сетевые технологии

Пример с трансляцией данных в шестнадцатеричном формате можно провести так же, но заменить команду на Destination или добавить еще один пайп на Repeater:

В результате будет создан файл, в котором можно будет обнаружить передаваемые данные в шестнадцатеричном формате:

что такое сокет сетевые технологии. Смотреть фото что такое сокет сетевые технологии. Смотреть картинку что такое сокет сетевые технологии. Картинка про что такое сокет сетевые технологии. Фото что такое сокет сетевые технологии

Как видно из тестового сценария использования, netcat не дает контролировать практически ничего, кроме направления данных. Нет ни разграничения доступа к ресурсам, которые пересылаются, ни возможности без дополнительных ухищрений работать с двумя сокетами, ни возможности контролировать действия сокета. Протестируем socat.

socat

Инструмент, который до сих пор поддерживается и имеет весьма обширный функционал по склейке каналов для взаимодействия. Разработчиками инструмент именуется как netcat++. Ниже приведем небольшой список того что можно перенаправить через socat:

Для повседневного использования достаточно опций, но если понадобится когда-то работать напрямую с серийным портом или виртуальным терминалом, то socat тоже умеет это делать. Полный перечень опций можно вызвать с помощью команды:

Помимо редиректов socat также можно использовать как универсальный сервер для расшаривания ресурсов, через него можно как через chroot ограничивать привилегии и доступ к директориям системы.

Чтобы комфортно пользоваться этим инструментом, нужно запомнить шаблон командной строки, который ожидает socat:

socat additionalOptions addr1 addr2

Попробуем провести трансляцию данных из сокета в сокет. Будем использовать для этого 1 машину. Перед началом эксперимента стоит отметить, что особенностью socat является то, что для его корректной работы нужно обязательно писать 2 адреса. Причем адрес не обязательно должен быть адресом, это может быть и приложение, и стандартный вывод на экран.

Например, чтобы использовать socat как netcat в качестве TCP сервера, можно запустить вот такую команду:

socat TCP-LISTEN:4545, STDOUT

Для коннекта можно использовать netcat:

При таком использовании, socat дает возможность пересылать сообщения в обе стороны, но если добавить флаг «-u», то общение будет только от клиента к серверу. Все серверные сообшения пересылаться не будут:

что такое сокет сетевые технологии. Смотреть фото что такое сокет сетевые технологии. Смотреть картинку что такое сокет сетевые технологии. Картинка про что такое сокет сетевые технологии. Фото что такое сокет сетевые технологии

Настроим более тонко наш сервер, добавив новые опции через запятую после используемого действия:

socat TCP-LISTEN:4545,reuseaddr,keepalive,fork STDOUT

Дополнительные параметры распространяются на те действия, которые socat может выполнять по отношению к адресу. Полный список опций можно найти здесь в разделе «SOCKET option group».

Таким образом socat дает практически полный контроль над состоянием сокетов и расшариваемых ресурсов.

Статья написана в преддверии старта курса Network engineer. Basic. Всех, кто желает подробнее узнать о курсе и карьерных перспективах, приглашаем записаться на день открытых дверей, который пройдет уже 4 февраля.

Источник

Начинающему сетевому программисту

В общем, посмотрев на всё это, я решил написать базовую статью по созданию простейшего клиент-сервер приложения на С++ под Windows с детальным описанием всех используемых функций. Это приложение будет использовать Win32API и делать незамысловатую вещь, а именно: передавать сообщения от клиента к серверу и обратно, или, иначе говоря – напишем программу по реализации чата для двух пользователей.

Сразу оговорюсь, что статья рассчитана на начинающих программистов, которые только входят в сетевое программирование под Windows. Необходимые навыки – базовое знание С++, а также теоретическая подготовка по теме сетевых сокетов и стека технологии TCP/IP.

Теория сокетов за 30 секунд для «dummies»

Начну всё-таки немного с теории в стиле «for dummies». В любой современной операционной системе, все процессы инкапсулируются, т.е. скрываются друг от друга, и не имеют доступа к ресурсам друг друга. Однако существуют специальные разрешенные способы взаимодействия процессов между собой. Все эти способы взаимодействия процессов можно разделить на 3 группы: (1) сигнальные, (2) канальные и (3) разделяемая память.

Для того, чтобы сокеты заработали под Windows, необходимо при написании программы пройти следующие Этапы:

Инициализация сокетных интерфейсов Win32API.

Инициализация сокета, т.е. создание специальной структуры данных и её инициализация вызовом функции.

«Привязка» созданного сокета к конкретной паре IP-адрес/Порт – с этого момента данный сокет (его имя) будет ассоциироваться с конкретным процессом, который «висит» по указанному адресу и порту.

Для серверной части приложения: запуск процедуры «прослушки» подключений на привязанный сокет.

Для клиентской части приложения: запуск процедуры подключения к серверному сокету (должны знать его IP-адрес/Порт).

Акцепт / Подтверждение подключения (обычно на стороне сервера).

Обмен данными между процессами через установленное сокетное соединение.

Закрытие сокетного соединения.

Итак, попытаемся реализовать последовательность Этапов, указанных выше, для организации простейшего чата между клиентом и сервером. Запускаем Visual Studio, выбираем создание консольного проекта на С++ и поехали.

Этап 0: Подключение всех необходимых библиотек Win32API для работы с сокетами

Сокеты не являются «стандартными» инструментами разработки, поэтому для их активизации необходимо подключить ряд библиотек через заголовочные файлы, а именно:

WinSock2.h – заголовочный файл, содержащий актуальные реализации функций для работы с сокетами.

WS2tcpip.h – заголовочный файл, который содержит различные программные интерфейсы, связанные с работой протокола TCP/IP (переводы различных данных в формат, понимаемый протоколом и т.д.).

Также нам потребуется прилинковать к приложению динамическую библиотеку ядра ОС: ws2_32.dll. Делаем это через директиву компилятору: #pragma comment(lib, “ws2_32.lib”)

Ну и в конце Этапа 0 подключаем стандартные заголовочные файлы iostream и stdio.h

Итого по завершению Этапа 0 в Серверной и Клиентской частях приложения имеем:

Обратите внимание: имя системной библиотеки ws2_32.lib именно такое, как это указано выше. В Сети есть различные варианты написания имени данной библиотеки, что, возможно, связано иным написанием в более ранних версиях ОС Windows. Если вы используете Windows 10, то данная библиотека называется именно ws2_32.lib и находится в стандартной папке ОС: C:/Windows/System32 (проверьте наличие библиотеки у себя, заменив расширение с “lib” на “dll”).

Этап 1: Инициализация сокетных интерфейсов Win32API

Прежде чем непосредственно создать объект сокет, необходимо «запустить» программные интерфейсы для работы с ними. Под Windows это делается в два шага следующим образом:

Нужно определить с какой версией сокетов мы работаем (какую версию понимает наша ОС) и

Запустить программный интерфейс сокетов в Win32API. Ну либо расстроить пользователя тем, что ему не удастся поработать с сокетами до обновления системных библиотек

Итого код Этапа 1 следующий:

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

Этап 2: Создание сокета и его инициализация

Тип сокета: обычно задается тип транспортного протокола TCP ( SOCK_STREAM ) или UDP ( SOCK_DGRAM ). Но бывают и так называемые «сырые» сокеты, функционал которых сам программист определяет в процессе использования. Тип обозначается SOCK_RAW

Тип протокола: необязательный параметр, если тип сокета указан как TCP или UDP – можно передать значение 0. Тут более детально останавливаться не будем, т.к. в 95% случаев используются типы сокетов TCP/UDP.

При необходимости подробно почитать про функцию socket() можно здесь.

Код Этапа 2 будет выглядеть так:

Этап 3: Привязка сокета к паре IP-адрес/Порт

Сокет уже существует, но еще неполноценный, т.к. ему не назначен внешний адрес, по которому его будут находить транспортные протоколы по заданию подключающихся процессов, а также не назначен порт, по которому эти подключающиеся процессы будут идентифицировать процесс-получатель.

В ней уже более понятные пользователю поля, а именно:

Технический массив на 8 байт ( sin_zero[8] )

Соответственно, ввод данных для структуры типа sockaddr_in выглядит следующим образом:

Создание структуры типа sockaddr_in : sockaddr_in servInfo;

Заполнение полей созданной структуры servInfo

В случае ошибки функция возвращает значение меньше 0.

Соответственно, если мы хотим привязать сокет к локальному серверу, то наш код по преобразованию IPv4 адреса будет выглядеть так:

erStat = inet_pton(AF_INET, “127.0.0.1”, &ip_to_num);

Результат перевода IP-адреса содержится в структуре ip_to_num. И далее мы передаем уже в нашу переменную типа sockaddr_in значение преобразованного адреса:

Этап 4 (для сервера): «Прослушивание» привязанного порта для идентификации подключений

После вызова данной функции исполнение программы приостанавливается до тех пор, пока не будет соединения с Клиентом, либо пока не будет возвращена ошибка прослушивания порта. Код Этапа 4 для Сервера:

Этап 4 (для Клиента). Организация подключения к серверу

Функция возвращает 0 в случае успешного подключения и код ошибки в ином случае.

Этап 5 (только для Сервера). Подтверждение подключения

Всё, соединение между Клиентом и Сервером установлено! Самое время попробовать передать информацию от Клиента к Серверу и обратно. Как мы в начале и договорились, мы будет реализовывать простейший чат между ними.

Этап 6: Передача данных между Клиентом и Сервером

Рассмотрим прототипы функций recv() и send() :

Флаги в большинстве случаев игнорируются – передается значение 0.

Функции возвращают количество переданных/полученных по факту байт.

Как видно из прототипов, по своей структуре и параметрам эти функции совершенно одинаковые. Что важно знать:

и та, и другая функции не гарантируют целостности отправленной/полученной информации. Это значит, что при реализации прикладных задач по взаимодействию Клиента и Сервера с их использованием требуется принимать дополнительные меры для контроля того, что все посланные байты действительно посланы и, что еще более важно, получены в том же объеме на другой стороне

предельно внимательно надо относиться к параметру «размер буфера». Он должен в точности равняться реальному количеству передаваемых байт. Если он будет отличаться, то есть риск потери части информации или «замусориванию» отправляемой порции данных, что ведет к автоматической поломке данных в процессе отправки/приёма. И совсем замечательно будет, если размер буфера по итогу работы функции равен возвращаемому значению функции – размеру принятых/отправленных байт.

В качестве буфера рекомендую использовать не классические массивы в С-стиле, а стандартный класс С++ типа char, т.к. он показал себя как более надежный и гибкий механизм при передаче данных, в особенности при передаче текстовых строк, где важен терминальный символ и «чистота» передаваемого массива.

Процесс непрерывного перехода от send() к recv() и обратно реализуется через бесконечный цикл, из которого совершается выход по вводу особой комбинации клавиш. Пример блока кода для Серверной части:

Пришло время показать итоговый рабочий код для Сервера и Клиента. Чтобы не загромождать и так большой текст дополнительным кодом, даю ссылки на код на GitHub:

Несколько важных финальных замечаний:

В итоговом коде я не использую проверку на точное получение отосланной информации, т.к. при единичной (не циклической) отсылке небольшого пакета информации накладные расходы на проверку его получения и отправку ответа будут выше, чем выгоды от такой проверки. Иными словами – такие пакеты теряются редко, а проверять их целостность и факт доставки очень долго.

При тестировании примера также видно, что чат рабочий, но очень уж несовершенный. Наиболее проблемное место – невозможность отправить сообщение пока другая сторона не ответила на твоё предыдущее сообщение. Суть проблемы в том, что после отсылки сообщения сторона-отправитель вызывает функцию recv(), которая, как я писал выше, блокирует исполнение последующего кода, в том числе блокирует вызов прерываний для осуществления ввода. Это приводит к тому, что набирать сообщение и что-то отправлять невозможно до тех пор, пока процесс не получит ответ от другой стороны, и вызов функции recv() не будет завершен. Благо введенная информация с клавиатуры не будет потеряна, а, накапливаясь в системном буфере ввода/вывода, будет выведена на экран как только блокировка со стороны recv() будет снята. Таким образом, мы реализовали так называемый прямой полудуплексный канал связи. Сделать его полностью дуплексным в голой сокетной архитектуре достаточно нетривиальная задача, частично решаемая за счет создания нескольких параллельно работающих потоков или нитей (threads) исполнения. Один поток будет принимать информацию, а второй – отправлять.

В последующих статьях я покажу реализацию полноценного чата между двумя сторонами (поможет разобраться в понятии «нити процесса»), а также покажу полноценную реализацию прикладного протокола по копированию файлов с Сервера на Клиент.

Источник

Разница между веб-сокетами и Socket.IO

что такое сокет сетевые технологии. Смотреть фото что такое сокет сетевые технологии. Смотреть картинку что такое сокет сетевые технологии. Картинка про что такое сокет сетевые технологии. Фото что такое сокет сетевые технологии

Доброго времени суток, друзья!

Веб-сокеты и Socket.IO, вероятно, являются двумя наиболее распространенными средствами коммуникации в режиме реального времени (далее — живое общение). Но чем они отличаются?

При построении приложения для живого общения наступает момент, когда необходимо выбрать средство для обмена данными между клиентом и сервером. Веб-сокеты и Socket.IO являются самыми популярными средствами живого общения в современном вебе. Какое из них выбрать? В чем разница между этими технологиями? Давайте выясним.

Веб-сокеты

Говоря о веб-сокетах, мы имеем ввиду протокол веб-коммуникации, представляющий полнодуплексный канал коммуникации поверх простого TCP-соединения. Проще говоря, эта технология позволяет установить связь между клиентом и сервером с минимальными затратами, позволяя создавать приложения, использующие все преимущества живого общения.

Например, представьте, что вы создаете чат: вам необходимо получать и отправлять данные как можно быстрее, верно? С этим прекрасно справляются веб-сокеты! Вы можете открыть TCP-соединение и держать его открытым сколько потребуется.

Веб-сокеты появились в 2010 году в Google Chrome 4, первый RFC (6455) опубликован в 2011.

Веб-сокеты используются в следующих случаях:

Socket.IO

Socket.IO — библиотека JavaScript, основанная (написанная поверх) на веб-сокетах… и других технологиях. Она использует веб-сокеты, когда они доступны, или такие технологии, как Flash Socket, AJAX Long Polling, AJAX Multipart Stream, когда веб-сокеты недоступны. Легкой аналогией может служить сравнение Fetch API и Axios.

Разница между веб-сокетами и Socket.IO

Главными преимуществами Socket.IO является следующее:

Во-первых, веб-сокеты поддерживаются всеми современными браузерами. Поэтому вы редко нуждаетесь в поддержке других технологий, предоставляемой Socket.IO.

Если говорить о сетевом трафике, то веб-сокеты отправляют всего два запроса:

В npm существует пакет «websocket-vs-socket.io», который позволяет сравнить сетевой трафик этих технологий:

Сетевой трафик веб-сокетов:

что такое сокет сетевые технологии. Смотреть фото что такое сокет сетевые технологии. Смотреть картинку что такое сокет сетевые технологии. Картинка про что такое сокет сетевые технологии. Фото что такое сокет сетевые технологии

Сетевой трафик Socket.IO:

что такое сокет сетевые технологии. Смотреть фото что такое сокет сетевые технологии. Смотреть картинку что такое сокет сетевые технологии. Картинка про что такое сокет сетевые технологии. Фото что такое сокет сетевые технологии

Пишем код

Простой сервер на веб-сокетах

В нашей программе на Node.js мы создадим сервер, работающий на порту 3001. При каждом подключении клиента мы будем присваивать ему уникальный ID. При отправке сообщения клиентом мы будем уведомлять его об успехе: [ ]:

Отлично! Но что если мы хотим рассылать сообщение каждому подключенному клиенту? Веб-сокеты не поддерживают рассылку по умолчанию. Это можно реализовать следующим образом:

Легко и просто! Как видите, WebSocket.Server хранит записи о каждом подключенном клиенте, поэтому мы можем сделать итерацию и отправить сообщение каждому. Вы можете протестировать код на компьютере (MacOS) или в браузере (Chrome).

Простой сервер на Socket.IO

Это было не сложно. Может ли Socket.IO сделать это еще проще? Как нам написать такой же сервер на Socket.IO?

Код получился почти наполовину короче! Как видите, метод «broadcast» не отправляет уведомление отправителю, поэтому мы вынуждены делать это вручную.

Существует проблема: код нельзя протестировать на обычном клиенте веб-сокетов. Это связано с тем, что, как отмечалось ранее, Socket.IO использует не чистые веб-сокеты, а множество технологий для поддержки всех возможных клиентов. Так как же нам проверить его работоспособность?

Необходимо использовать специальный клиент. В приведенном примере мы загружаем его из CDN. Этот клиент позволяет нам провести быстрые (грязные) тесты в браузере.

Источник

Вебсокеты: боевое применение

что такое сокет сетевые технологии. Смотреть фото что такое сокет сетевые технологии. Смотреть картинку что такое сокет сетевые технологии. Картинка про что такое сокет сетевые технологии. Фото что такое сокет сетевые технологииВебсокеты — это прогрессивный стандарт полнодуплексной (двусторонней) связи с сервером по TCP-соединению, совместимый с HTTP. Он позволяет организовывать живой обмен сообщениями между браузером и веб-сервером в реальном времени, причем совершенно иным способом, нежели привычная схема «запрос URL — ответ». Когда два года назад я присматривался к этому стандарту, он был еще в зачаточном состоянии. Существовал лишь неутвержденный набросок черновика и экспериментальная поддержка некоторыми браузерами и веб-серверами, причем в Файрфоксе он был по умолчанию отключен из-за проблем с безопасностью. Однако теперь ситуация изменилась. Стандарт приобрел несколько ревизий (в том числе без обратной совместимости), получил статус RFC (6455) и избавился от детских болезней. Во всех современных браузерах, включая IE10, заявлена поддержка одной из версий протокола, и есть вполне готовые к промышленному использованию веб-серверы.

Я решил, что настало время попробовать это на живом проекте. И теперь делюсь, что из этого вышло.

Суть задачи

На моем личном небольшом сайте Клавогонки.ру есть центральная часть — список действующих в данных момент игр-заездов. Список крайне динамичный: новый заезд создается игроками каждые несколько секунд, иногда несколько в секунду. Заезды начинаются с отсчета времени, по завершению перемещаются из раздела открытых игр в раздел активных. После выхода всех игроков заезд убирается со страницы. В один заезд заходит от одного и иногда до ста игроков, что требуется отображать тут же.

что такое сокет сетевые технологии. Смотреть фото что такое сокет сетевые технологии. Смотреть картинку что такое сокет сетевые технологии. Картинка про что такое сокет сетевые технологии. Фото что такое сокет сетевые технологии

Как это работало раньше

Изначально, когда появилась необходимость сделать эту часть функциональности сайта, возникло много трудностей с динамическим обновлением списка. На странице списка могут находиться десятки человек одновременно, каждый из которых хочет видеть свежую картину. У многих заездов может быть таймаут отсчета от создания до старта всего 10-20 секунд, и чтобы успеть присоединиться к ним, обновление должно происходить достаточно живо.

Обновление всей страницы по таймауту здесь не подходило вообще никак, и нужно было искать другие варианты (тут надо сделать ремарку, что использовать флеш на сайте не хотелось без очень сильной на то необходимости).

Самым очевидным и простым решением здесь на первый взгляд казался long-polling — висящее подключение к серверу, которое обрывается в момент поступления нового события и переоткрывается заново. Однако после некоторых тестов этот вариант тоже оказался нежизнеспособным: события поступали непрерывным потоком, ведь клиенту нужно сообщать не только о создании новой игры, но и об изменении параметров всех игр (например, старт таймаута, смена статуса, состава игроков), и количество запросов начало вызывать определенную степень недовольства у сервера. Да и оверхед на открытие-закрытие запросов тоже выходил немаленький.

HTTP-streaming не получилось использовать из-за проблем с прокси-серверами у многих пользователей.

Поэтому я остановился на простом варианте обновления содержимого страницы по таймауту раз в 3 секунды через ajax-запросы. На сервере текущие данные кешировались и отдавались клиентам из кэша в json, при этом для экономии трафика отдавался не весь список каждый раз, а лишь измененные данные через систему версионирования (увеличилась версия по сравнению с запрашиваемой — отдаем новую информацию о заезде, иначе отдаем только текущий номер версии).

Система показала себя неплохо и проработала долгое время. Однако был большой минус — очень трудно зайти в заезд с 10-секундным таймаутом до старта. Кроме того, это совсем не соответствовало духу динамичной гоночной онлайн-игры и выглядело не слишком технологично в целом.

Увидеть эту страницу в ее старом варианте вы можете по этой ссылке.

Как это работает сейчас

Если говорить кратко, вебсокеты позволили внести драйв в весь этот процесс.

Для начала был выбран сервер, который должен жить в связке с действующим игровым бэкэндом. По ряду причин я выбрал для этого node.js — событийно-ориентированная модель и хорошо развитые коллбэки в javascript идеально подошли для этой задачи.

Общей средой общения между php-бэкэндом и сервером на node.js стали pubsub-каналы redis. При создании новой игры или любом действии, изменяющем данные, php делает примерно следующее (код здесь и далее сильно упрощен):

Redis работает как отдельный демон на отдельном TCP-порте и принимает/рассылает сообщения от любого количества подключенных клиентов. Это дает возможность хорошо масштабировать систему, невзирая на количество процессов (ну и серверов, если думать оптимистично) php и node.js. Сейчас крутится примерно 50 php-процессов и 2 node.js-процесса.

На стороне node.js при старте идет подключение к прослушке redis-канала под названием gamelist :

Для работы с клиентами используется обвязочная библиотека Socket.IO (upd: товарищи Voenniy и Joes в комментах говорят, что есть более качественные альтернативы вроде SockJS и Beseda, что вполне может быть правдой). Она позволяет использовать вебсокеты как основной транспорт, откатываясь при этом на другие транспорты вроде флеша или xhr-polling если браузер не поддерживает вебсокеты. Вдобавок, она упрощает работу с клиентами в целом, например дает API для мультиплексирования и разделения подключенных клиентов по разным псевдокаталогам (каналам), позволяет именовать события и некоторые другие плюшки.

При поступлении по redis-каналу события из бэкэнда оно всячески предварительно анализируется и потом отсылается всем подключенным клиентам в gamelistSockets :

Браузер получает событие ровно таким же образом и рендерит необходимые изменения на странице.

Принцип совершенно прост и ясен. Продвинутые технологии в основе этой схемы позволяют сильно упростить процесс и сосредоточиться на логике самой работы. Хотя пришлось несколько повозиться с переделкой некоторых частей php-кода для работы в идеологии «сообщаем об изменении, а не о состоянии», а также вынести домен вебсокетов на отдельную от основной машину (чтобы не мучиться с разделяющим прокси на 80 порту), но в сухом остатке плюсы вышли очень существенными:

Посмотреть на то, что получилось в итоге, вы можете здесь. Разница видна невооруженным взглядом.

В качестве бонуса две таблички, небольшая статистика по аудитории Клавогонок, браузеры и используемые в Socket.IO транспорты:

БраузерДоляТранспортДоля
Chrome51%websocket90%
Firefox20%xhr-polling5%
Opera15%flashsocket4%
IE (примерно пополам 8 и 9)6%jsonppolling1%

Как видно, вполне готово к употреблению.

Тут могла бы быть заключительная резюмирующая часть с итогами, библиографией и моралью. Но я сэкономлю ваше время и скажу просто: вебсокеты — это очень круто!

Источник

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *