Что такое udp сокет

Обновлено: 06.07.2024

Сокеты — это технология передачи данных низкого уровня, на основе которой реализованы многие сетевые протоколы. UWP предоставляет классы сокетов TCP и UDP для клиент-серверных или одноранговых приложений, если устанавливаются долгосрочные подключения или установленное подключение не требуется.

Как последствие сетевой изоляции WIndows запрещает установку подключения сокета (Sockets или WinSock) между двумя приложениями UWP, работающими на одном компьютере, через локальный петлевой адрес (127.0.0.0) либо путем явного указания локального IP-адреса. Дополнительные сведения о механизмах, с помощью которых приложения UWP могут взаимодействовать друг с другом, см. в разделе Связь между приложениями.

Создание базового клиента и сервера сокета TCP

Для постоянных подключений сокет протокола TCP обеспечивает в сети низкоуровневую двунаправленную передачу данных. Сокеты TCP широко используются большинством сетевых протоколов в Интернете. Чтобы продемонстрировать базовые операции TCP, в следующем примере кода реализованы отправка и получение данных через TCP объектами StreamSocket и StreamSocketListener, на основе которых создаются эхо-клиент и сервер.

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

Потребуется объявить возможность приложения в своем проекте. Откройте исходный файл манифеста пакета приложения (файл Package.appxmanifest ) и на вкладке "Возможности" установите флажок Частные сети (клиент и сервер). Вот как это выглядит в разметке Package.appxmanifest .

Вместо privateNetworkClientServer можно объявить internetClientServer , если подключение осуществляется по Интернету. И StreamSocket, и StreamSocketListener требуют, чтобы была объявлена одна из этих возможностей приложения.

Эхо-клиент и сервер на основе сокетов TCP

Создайте StreamSocketListener и начните слушать входящие подключения TCP. Событие StreamSocketListener.ConnectionReceived создается всякий раз, когда клиент устанавливает подключение к прослушивателю StreamSocketListener.

Кроме того, создайте сокет StreamSocket, установите подключение к серверу, отправьте запрос и получите ответ.

Ссылки на StreamSockets в продолжениях C++ PPL (в первую очередь применимо к C++/CX)

Это неприменимо в случае использования сопрограмм C++/WinRT и передачи параметров по значению. Рекомендации по передаче параметров см. в разделе Параллельная обработка и асинхронные операции с помощью C++/WinRT.

StreamSocket остается активным, пока в его потоке ввода/вывода выполняются активные операции чтения/записи (рассмотрим для примера StreamSocketListenerConnectionReceivedEventArgs.Socket, доступ к которому осуществляется в обработчике событий StreamSocketListener.ConnectionReceived). При вызове DataReader.LoadAsync (или ReadAsync/WriteAsync/StoreAsync ) он хранит ссылку на сокет (через поток ввода сокета) до тех пор, пока обработчик событий Completed (при наличии) метода LoadAsync не завершит выполнение.

Библиотека параллельных шаблонов (PPL) не планирует встроенное продолжение задач по умолчанию. Другими словами, добавление задачи продолжения (с task::then() ) не гарантирует, что задача продолжения будет выполняться во встроенном режиме в качестве завершающего обработчика.

С точки зрения StreamSocket завершающий обработчик завершит выполнение (и сокет станет готовым к ликвидации) до запуска основной части продолжения. Таким образом, чтобы предотвратить удаление сокета, если вы хотите использовать его в этом продолжении, необходимо ссылаться на сокет напрямую (через захват лямбда-функции) и использовать его, или косвенно (продолжая осуществлять доступ к args->Socket внутри продолжения), или обеспечить принудительное выполнение задач продолжения в коде. Эту первую технику можно наблюдать в действии (захват лямбда-функции) в примере StreamSocket. Код C++/CX в разделе Создание базового клиента и сервера TCP-сокета выше использует второй способ. Он возвращает запрос в качестве ответа и осуществляет доступ к args->Socket из одного из продолжений самого глубокого уровня.

Третий способ подходит в тех случаях, когда не нужно выводить ответ. Параметр task_continuation_context::use_synchronous_execution() используется для принудительного выполнения основной части продолжения внутри PPL. Этот пример кода демонстрирует, как это сделать.

Создание простейших клиента и сервера для UDP-сокетов

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

Чтобы продемонстрировать базовые операции UDP, пример кода ниже показывает класс DatagramSocket, который используется для отправки и получения данных через UDP с целью формирования эхо-клиента и сервера. Создайте новый проект и поместите представленный ниже код клиента и сервера в один проект. Как и в случае с сокетом TCP, необходимо объявить возможность приложения Частные сети (клиент и сервер).

Создание эхо-клиента и эко-сервера с использованием сокетов UDP

Фоновые операции и брокер сокета

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

Пакетные отправки

Каждый раз, когда вы выполняется запись в поток, связанный с сокетом, происходит переход из режима пользователя (обычный код) в режим ядра (где работает сетевой стек). Если записывается много буферов одновременно, повторяющиеся переходы создают значительную нагрузку. Чтобы отправлять несколько буферов данных одновременно, избегая такой нагрузки, можно собирать отправляемые данные в пакеты. Это особенно полезно, если ваше приложение поддерживает VoIP, VPN или другие задачи, предполагающие максимально эффективное перемещение больших объемов данных.

В этом разделе показано несколько техник пакетных отправок, которые можно использовать с сокетом StreamSocket или подключенным сокетом DatagramSocket.

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

  • Вы не можете изменять содержимое экземпляров IBuffer, записанных до завершения асинхронной записи.
  • Шаблон FlushAsync работает только с StreamSocket.OutputStream и DatagramSocket.OutputStream.
  • Шаблон FlushAsync работает только в Windows 10 и более поздних версиях.
  • В других случаях следует использовать Task.WaitAll вместо шаблона FlushAsync.

Совместное использование порта для DatagramSocket

Можно настроить сокет DatagramSocket для совместного существования с другими многоадресными сокетами Win32 или UWP, связанными с тем же адресом/портом. Для этого необходимо задать для DatagramSocketControl.MulticastOnly значение true , прежде чем привязывать или подключать сокет. Доступ к экземпляру DatagramSocketControl осуществляется из объекта DatagramSocket через свойство DatagramSocket.Control.

Предоставление сертификата клиента с классом StreamSocket

Класс StreamSocket поддерживает возможность использования протокола SSL/TLS для проверки подлинности сервера, к которому обращается клиентское приложение. В некоторых случаях клиентское приложение также должно пройти проверку подлинности на сервере с помощью сертификата клиента SSL/TLS. Можно предоставить клиентский сертификат со свойством StreamSocketControl.ClientCertificate, прежде чем привязывать или подключать сокет (его необходимо задать до начала подтверждения протокола SSL/TLS). Доступ к экземпляру StreamSocketControl осуществляется из объекта StreamSocket через свойство StreamSocket.Control. Если сервер запрашивает сертификат клиента, Windows ответит, воспользовавшись предоставленным клиентским сертификатом.

Используйте переопределение метода StreamSocket.ConnectAsync, которое принимает значение SocketProtectionLevel, как показано в примере минимального кода.

Как указано в комментарии в примерах кода ниже, чтобы код работал, в проекте должна быть объявлена возможность приложения sharedUserCertificates.

Обработка исключений

Ошибка, обнаруженная в операции DatagramSocket, StreamSocket или StreamSocketListener, возвращается в виде значения HRESULT. Можно передать значение HRESULT методу SocketError.GetStatus, чтобы преобразовать его в значение перечисления SocketErrorStatus.

Большинство значений перечисления SocketErrorStatus соответствуют ошибке, возвращаемой стандартной операцией с сокетами Windows. Ваше приложение может включать значения перечисления SocketErrorStatus, чтобы по-разному действовать в зависимости от причины исключения.

Для ошибок при проверке параметров можно использовать также значение HRESULT из исключения, чтобы получить подробные сведения об ошибке. Возможные значения HRESULT перечислены в Winerror.h , который находится в вашей установке SDK (например, в папке C:\Program Files (x86)\Windows Kits\10\Include\<VERSION>\shared ). Для многих ошибок при проверке параметров HRESULT возвращает значение E_INVALIDARG.

Конструктор HostName может создать исключение, если переданная строка не является допустимым именем узла. Например, он содержит недопустимые символы, что вероятно, если имя узла вводится в приложении пользователем. Создайте HostName внутри блока try/catch. В этом случае приложение может сообщить пользователю об ошибке и запросить новое имя узла.

В центре внимания статьи:

IP-адрес, номер порта .

Внедрить клиент / сервер UDP

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

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

Понять процесс связи на сетевом уровне:


Сначала узнайте IP:

(IP: IP-адрес интернет-протокола)


При общении IP делится на исходный IP и целевой IP,

В отличие от экспресс-доставки: сетевое взаимодействие эквивалентно отправке и получению экспресс-доставки. IP - это адрес получателя / отправителя. Недостаточно просто знать адрес, но также знать, кто отправитель? Это контрастирует с концепцией номеров портов в сети.Номер порта идентифицирует процесс и сообщает операционной системе, в какую программу в настоящее время передаются данные для анализа.

Номер порта:

Номер порта (порт) - это содержимое протокола транспортного уровня.

Номер порта - 2-байтовое 16-битное целое число;

IP-адрес + номер порта могут идентифицировать определенный процесс определенного хоста в сети;

Номер порта может быть занят только одним процессом.

Номер порта и процесс:

Процесс имеет уникальный идентификатор pid, и номер порта также может идентифицировать процесс;

Процесс может быть привязан к нескольким номерам портов, а номер порта не может быть привязан к нескольким процессам.

  • Номер исходного порта и номер порта назначения

В сегменте данных протокола транспортного уровня (TCP / IP) есть два номера порта, которые называются, соответственно, номером порта источника и номером порта назначения, которые описывают «Чьи данные от? Кому?»

(TCP) Протокол управления передачей, ориентированный на соединение. Это универсальный протокол, обеспечивающий надежную передачу данных.

Протокол транспортного уровня

Ориентирован на байтовый поток

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

Протокол транспортного уровня

Ориентированный на дейтаграммы

Сетевой порядок байтов:


  • Как определить адрес сетевого потока данных?


Фактически, легко понять эту проблему, которая является более сложной большой и маленькой проблемой в языке C.

Передатчик отправляет адрес памяти в порядке от младшего к большему;

Принимающий хост сохраняет адрес памяти от младшего к старшему;

TCP / IP предусматривает: сетевой поток данных должен принимать порядок байтов с прямым порядком байтов, а именно:Старший байт наземного адреса;

Независимо от того, является ли хост прямым или прямым порядком байтов, он должен соответствовать правилам TCP / IP;

Если передатчик является прямым порядком байтов, сначала преобразуйте данные в прямой порядок байтов перед отправкой.

socket API:

Параметр 1 (домен):Выберите семейство протоколов, используемое созданным сокетом;
AF_INET: протокол IPv4;
AF_INET6: протокол IPv6;
AF_LOCAL: протокол домена Unix;
AF_ROUTE: сокет маршрутизации;
AF_KEY: гнездо для ключа.
Параметр 2 (тип):Укажите тип розетки, выбранные типы:
SOCK_STREAM: сокет байтового потока;
SOCK_DGRAM: сокет датаграммы;
SOCK_RAW: исходный сокет.
procotol: конкретный используемый протокол, обычно используется протокол по умолчанию (NULL).

Параметр 1 (розетка): Дескриптор сокета (номер сокета), возвращенный вызовом socket () и не связанный.
Параметр 2 (адрес):Указатель на адрес определенного протокола.
Параметр 3 (address_len):Длина адресной структуры выше.
возвращаемое значение:Ошибки нет, bind () возвращает 0, иначе - SOCKET_ERROR.

Параметр 1 (sockfd):Дескриптор сокета (номер сокета), возвращенный вызовом socket () и не связанный.
Параметр 2 (отставание):Размер отслеживаемой очереди портов.

Параметр 1 (розетка): Дескриптор сокета (номер сокета), возвращенный вызовом socket () и не связанный.
Параметр 2 (адрес):Указатель на адрес определенного протокола.
Параметр 3 (адрес):Длина адресной структуры выше.
возвращаемое значение:Ошибки нет, bind () возвращает 0, иначе - SOCKET_ERROR.

Параметры (fd):Дескриптор сокета (номер сокета), возвращенный вызовом socket () и не связанный.

Socket API - это абстрактный интерфейс сетевого программирования, подходящий для различных основных сетевых протоколов, таких как IPv4, IPv6, .

Простая сетевая программа TCP:
  • Блок-схема выполнения клиент-серверной программы TCP:


Простая сетевая программа UDP:


  • По сравнению с TCP, UDP имеет низкую безопасность и не имеет связи. Поэтому в реализации UDP отсутствует операция подключения и приема подключений. Таким образом, при отправке и получении данных вы больше не можете использовать send () и recvfrom (), но используйте sendto () и recvto () для отправки и получения данных.

Параметр 1 (sockfd):Дескриптор сокета (номер сокета), возвращенный вызовом socket () и не подключенный
Параметр 2 (buf):Указатель на буфер, в котором хранятся отправленные данные
Параметр 3 (len):Длина буфера.
** Параметр 4 (флаги): ** Значение флагов равно 0 или другому.

Параметр 1 (sockfd):Дескриптор сокета (номер сокета), возвращенный вызовом socket () и не подключенный
Параметр 2 (buf):Указатель на буфер, в котором хранятся полученные данные
Параметр 3 (len):Длина буфера
** Параметр 4 (флаги): ** Значение флагов равно 0 или другому.

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

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

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

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

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

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

socket()¶

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

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

  • AF_INET для сетевого протокола IPv4
  • AF_INET6 для IPv6
  • AF_UNIX для локальных сокетов (используя файл)

type

  • SOCK_STREAM (надёжная потокоориентированная служба (сервис) или потоковый сокет)
  • SOCK_DGRAM (служба датаграмм или датаграммный сокет)
  • SOCK_RAW (Сырой сокет — сырой протокол поверх сетевого уровня).

protocol

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

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

Пример на Python

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

  1. sockfd — дескриптор, представляющий сокет при привязке
  2. serv_addr — указатель на структуру sockaddr, представляющую адрес, к которому привязываем.
  3. addrlen — поле socklen_t, представляющее длину структуры sockaddr.

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

Пример на Python

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

listen()¶

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

  1. sockfd — корректный дескриптор сокета.
  2. backlog — целое число, означающее число установленных соединений, которые могут быть обработаны в любой момент времени. Операционная система обычно ставит его равным максимальному значению.

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

Пример на Python

accept()¶

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

  1. sockfd — дескриптор слушающего сокета на принятие соединения.
  2. cliaddr — указатель на структуру sockaddr, для принятия информации об адресе клиента.
  3. addrlen — указатель на socklen_t, определяющее размер структуры, содержащей клиентский адрес и переданной в accept(). Когда accept() возвращает некоторое значение, socklen_t указывает сколько байт структуры cliaddr использовано в данный момент.

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

Пример на Python

connect()¶

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

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

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

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

Пример на Python

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

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

Java

Сокеты — это абстракция самого низкого уровня для программистов, работающих в области сетевого программирования. Существует в основном два способа (протокола) того, как должна происходить коммуникация сокетов.

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

Он называется TCP (Transfer Control Protocol). В противоположность этому, другой способ имеет очень мало правил, и поэтому он ускоряет общение, но не гарантирует точность. Он называется UDP (User Datagram Protocol). Если вам будет дан шанс выбрать один из них, какой вы выберете?

Я не собираюсь подробно обсуждать разницу между TCP и UDP, потому что это выходит за рамки данной статьи. Тем не менее, когда мы хотим, чтобы коммуникация была точной, мы должны воспользоваться TCP, потому что это помогает обеспечить бесперебойную связь.

Если вы знакомы с TCP, то наверняка знаете, что он реализует различные механизмы, такие как управление потоком, контроль ошибок, контроль перегрузки и т.д. Однако, когда нашим главным приоритетом является быстрая коммуникация, а не точная, выбор должен быть сделан в пользу UDP.

В этой статье мы узнаем, что такое UDP-сокеты и как продемонстрировать коммуникацию UDP-сокетов, используя Java.

Но почему именно UDP?


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

Неспособность поставлять контент в режиме реального времени может критически сказаться на росте поставщика потоковой передачи и его позиции на рынке.

Кроме того, нет никакой пользы в повторной трансляции точных данных, даже если контент был поврежден на пути к конечному пользователю, просто потому, что они больше не являются “контентом в реальном времени”. По этим причинам при взаимодействии в реальном времени UDP предпочтительнее TCP.

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


  1. socket() — прежде всего сокет определяется как для сервера, так и для клиента. Это не обязательно должно происходить одновременно. Чтобы объяснение было исчерпывающим, я буду на каждом этапе обсуждать действия как сервера, так и клиента.
  2. bind() — сокету, который определен, присваивается идентификатор и порт на работающей машине. Для клиентского сокета это необязательно, потому что даже если клиентский сокет не привязан, привязка осуществляется автоматически всякий раз, когда клиент инициирует подключение к серверу.
  3. recvfrom() — после привязки к порту компьютера серверный сокет ожидает подключения от клиентского сокета. Тем временем дальнейшее выполнение текущего потока останавливается (блокируется) до тех пор, пока серверный сокет не получит соединение. То же самое происходит и с клиентским сокетом при ожидании ответа сервера.
  4. sendto() — после соединения с клиентом серверный сокет отправляет данные клиенту. Этот же метод используется клиентским сокетом для выполнения запроса на подключение к серверу.
  5. close() — после успешного обмена данными оба сокета закрываются, т.е. освобождаются ресурсы системы, выделенные для сокетов.

Коммуникация UPD-сокетов в действии

Классы DatagramPacket и DatagramSocket в Java поддерживают использование коммуникации UDP-сокетов на уровне приложения. Давайте напишем простой сервер и клиент на Java, которые взаимодействуют друг с другом через UDP-сокеты.

В этом примере серверный сокет получает данные типа String от клиента и отправляет заглавную строку обратно клиенту.

Поскольку мы уже осведомлены об этапах коммуникации UDP-сокетов, я поместил комментарии в обе Java-программы, чтобы объяснить код, а не использовать длинные абзацы. Этот способ также поможет вам быстрее понять код, пока вы будете его читать.

Построение серверного UDP-сокета

Создание клиентского UDP-сокета

Запуск программ: демонстрация работы сокетов

Поскольку мы уже создали и сервер, и клиента, давайте запустим обе программы и посмотрим их в действии. Сначала запустите программу UDPServer.java , а затем UDPClient.java .

Вы увидите на консоли/терминале вывод каждой программы, как это показано ниже. Это гарантирует, что между нашими сервером и клиентом произошла успешная коммуникация сокетов.

UDPServer.java

UDPClient.java

Вот наше руководство и подошло к концу. Из этой статьи мы узнали, что такое коммуникация UDP-сокетов и как ее продемонстрировать на Java. Я искренне надеюсь, что информация вам пригодится.

Читайте также: