что такое пакет данных

Что такое пакет данных

Ключевой термин: пакет.

информацию, синхронизирующую передачу.

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

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

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

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

При разбиении данных на пакеты сетевая операционная система добавляет к каждому пакету специальную управляющую информацию. Она обеспечивает:

передачу исходных данных небольшими блоками;

сбор данных в надлежащем порядке (при их получении);

проверку данных на наличие ошибок (после сборки).

Пакеты могут содержать несколько типов данных:

информацию (например, сообщения или файлы);

определенные виды данных и команд, управляющих компьютером (например, запросы к службам);

коды управления сеансом (например, запрос на повторную передачу для исправления ошибки).

Некоторые компоненты являются обязательными для всех типов пакетов:

адрес источника (source), идентифицирующий компьютер-отправитель;

адрес местоназначения (destination), идентифицирующий компьютер-получатель;

инструкции сетевым компонентам о дальнейшем маршруте данных;

информация компьютеру-получателю о том, как объединить передаваемый пакет с остальными, чтобы получить данные в исходном виде;

информация для проверки ошибок, обеспечивающая корректность передачи.

Компоненты пакета группируются в три раздела: заголовок, данные и трейлер.

Рисунок 3.3.3. Компоненты пакета

сигнал, «говорящий» о том, что передается пакет;

информацию, синхронизирующую передачу.

Так как обычно размер исходных данных гораздо больше 4 Кб, для помещения в пакет их необходимо разбивать на меньшие блоки. При передаче объемного файла может потребоваться много пакетов.

Рисунок 3.3.4. Сформированный пакет

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

Процесс формирования пакета начинается на Прикладном уровне модели OSI, т.е. там, где «рождаются» данные. Информация, которую надо переслать по сети, проходит сверху вниз все семь уровней, начиная с Прикладного.

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

Рисунок 3.3.5. Формирование пакета

Большинство пакетов в сети адресуется конкретному компьютеру, и, как результат, только он один реагирует на них. Каждая плата сетевого адаптера «видит» все пакеты, передаваемые по сегменту кабеля, но только при совпадении адреса пакета с адресом компьютера она прерывает его работу. Используется также и широковещательная адресация (broadcast addressing). На пакет с таким типом адреса одновременно реагирует множество компьютеров в сети.

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

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

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

Компьютер может отбирать определенные пакеты на основе некоторых критериев, например адреса.

При разбиении данных на пакеты сетевая операционная система добавляет к каждому пакету специальную управляющую информацию.

Компоненты пакета группируются в три раздела: заголовок, данные и трейлер.

Формат и размер пакета зависят от типа сети.

Процесс формирования пакета начинается на Прикладном уровне модели OSI.

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

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

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

Используется также и широковещательная адресация (broadcast addressing). На пакет с таким типом адреса одновременно реагирует множество компьютеров в сети.

В правильной рассылке пакетов ключевую роль играют две функции: продвижение пакетов и фильтрация пакетов.

Вопросы для самоконтроля

Объясните термин: «пакет».

Для чего данные, передаваемые по компьютерной сети, разбивают на пакеты?

Какую функцию играет специальная управляющая информация, которую сетевая операционная система добавляет к каждому пакету?

Какова структура пакета?

Какие функции в правильной рассылке пакетов играют ключевую роль?

Что означает термин «продвижение» пакетов?

Что означает термин «фильтрация» пакетов?

IP-пакет состоит из заголовка и поля данных. Заголовок, как правило, имеющий длину 20 байт, имеет следующую структуру (рис. 3.3.7).

Поле Номер версии (Version), занимающее 4 бит, указывает версию протокола IP. Сейчас повсеместно используется версия 4 (IPv4), и готовится переход на версию 6 (IPv6).

Поле Длина заголовка (IHL) IP-пакета занимает 4 бит и указывает значение длины заголовка, измеренное в 32-битовых словах. Обычно заголовок имеет длину в 20 байт (пять 32-битовых слов), но при увеличении объема служебной информации эта длина может быть увеличена за счет использования дополнительных байт в поле Опции (IP Options). Наибольший заголовок занимает 60 октетов.

Рисунок 3.3.6. Структура заголовка IP-пакета

Поле Общая длина (Total Length) занимает 2 байта и означает общую длину пакета с учетом заголовка и поля данных. Максимальная длина пакета ограничена разрядностью поля, определяющего эту величину, и составляет 65 535 байт, однако в большинстве хост-компьютеров и сетей столь большие пакеты не используются. При передаче по сетям различного типа длина пакета выбирается с учетом максимальной длины пакета протокола нижнего уровня, несущего IP-пакеты. Если это кадры Ethernet, то выбираются пакеты с максимальной длиной в 1500 байт, умещающиеся в поле данных кадра Ethernet. В стандарте предусматривается, что все хосты должны быть готовы принимать пакеты вплоть до 576 байт длиной (приходят ли они целиком или по фрагментам). Хостам рекомендуется отправлять пакеты размером более чем 576 байт, только если они уверены, что принимающий хост или промежуточная сеть готовы обслуживать пакеты такого размера.

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

Поле Флаги (Flags) занимает 3 бита и содержит признаки, связанные с фрагментацией. Установленный бит DF (Do not Fragment) запрещает маршрутизатору фрагментировать данный пакет, а установленный бит MF (More Fragments) говорит о том, что данный пакет является промежуточным (не последний) фрагментом. Оставшийся бит зарезервирован.

Поле Смещение фрагмента (Fragment Offset) занимает 13 бит и задает смещение в байтах поля данных этого пакета от начала общего поля данных исходного пакета, подвергнутого фрагментации. Используется при сборке/разборке фрагментов пакетов при передачах их между сетями с различными величинами MTU. Смещение должно быть кратно 8 байт.

Поле Время жизни (Time to Live) занимает один байт и означает предельный срок, в течение которого пакет может перемещаться по сети. Время жизни данного пакета измеряется в секундах и задается источником передачи. На маршрутизаторах и в других узлах сети по истечении каждой секунды из текущего времени жизни вычитается единица; единица вычитается и в том случае, когда время задержки меньше секунды. Поскольку современные маршрутизаторы редко обрабатывают пакет дольше, чем за одну секунду, то время жизни можно считать равным максимальному числу узлов, которые разрешено пройти данному пакету до того, как он достигнет места назначения. Если параметр времени жизни станет нулевым до того, как пакет достигнет получателя, этот пакет будет уничтожен. Время жизни можно рассматривать как часовой механизм самоуничтожения. Значение этого поля изменяется при обработке заголовка IP-пакета.

Идентификатор Протокол верхнего уровня (Protocol) занимает один байт и указывает, какому протоколу верхнего уровня принадлежит информация, размещенная в поле данных пакета (например, это могут быть сегменты протокола TCP, дейтаграммы UDP, пакеты ICMP или OSPF). Значения идентификаторов для различных протоколов приводятся в документе RFC «Assigned Numbers».

Поле Опции (IP Options) является необязательным и используется обычно только при отладке сети. Механизм опций предоставляет функции управления, которые необходимы или просто полезны при определенных ситуациях, однако он не нужен при обычных коммуникациях. Это поле состоит из нескольких подполей, каждое из которых может быть одного из восьми предопределенных типов. В этих подполях можно указывать точный маршрут прохождения маршрутизаторов, регистрировать проходимые пакетом маршрутизаторы, помещать данные системы безопасности, а также временные отметки. Так как число подполей может быть произвольным, то в конце поля Опции должно быть добавлено несколько байт для выравнивания заголовка пакета по 32-битной границе.

Поле Выравнивание (Padding) используется для того, чтобы убедиться в том, что IP-заголовок заканчивается на 32-битной границе. Выравнивание осуществляется нулями.

Формат пакета протокола IPX

Пакет протокола IPX имеет гораздо более простую структуру по сравнению с пакетом IP, что, собственно, и отражает меньшие функциональные возможности протокола IPX.

IPX-пакет имеет следующие поля.

Управление транспортом (Transport control) имеет длину 8 бит. Это поле определяет время жизни пакета в хопах. IPX-пакет может пересечь до 15 маршрутизаторов. Протокол IPX устанавливает это однобайтовое поле в 0 до начала передачи, а затем увеличивает его на 1 каждый раз, когда пакет проходит через маршрутизатор. Eu,ui счетчик превысит 15, то пакет аннулируется.

Поле данных (Data). Может занимать от 0 до 546 байт. Поле данных нулевой длины может использоваться в служебных пакетах, например, для подтверждения получения предыдущего пакета.

Из анализа формата пакета можно сделать некоторые выводы об ограничениях протокола IPX.

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

Большие накладные расхдды на служебную информацию. Сравнительно небольшая максимальная длина поля данных IPX-пакета (546 байт при длине заголовка 30 байт) приводит к тому, что как минимум 5 % данных являются служебными.

Время жизни пакета ограничено числом 15, что может оказаться недостаточным для большой сети (для сравнения, в IP-сетях пакет может пройти до 255 промежуточных маршрутизаторов).

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

Кроме того, некоторые недостатки сетей Novell связаны не с протоколом IPX, a со свойствами других протоколов стека IPX/SPX. Многие недостатки проявляются при работе стека IPX/SPX на медленных глобальных линиях связи, и это закономерно, так как ОС NetWare оптимизировалась для работы в локальной сети.

Например, неэффективная работа по восстановлению потерянных и искаженных пакетов на низкоскоростных глобальных каналах обусловлена тем, что протокол NCP, который выполняет эту работу, использует метод получения квитанций с простоями. В локальных сетях со скоростью 10 Мбит/с такой метод работал вполне эффективно, а на медленных каналах время ожидания квитанции заметно тормозит работу передающего узла.

В версиях ОС NetWare до 4.0 соответствие символьных имен серверов их сетевым адресам устанавливалось только с помощью широковещательного протокола Service Advertising Protocol (SAP). Однако широковещательные рассылки заметно засоряют медленные глобальные каналы. Модернизируя свой стек для применения в крупных корпоративных сетях, компания Novell использует теперь справочную службу NDS (NetWare Directory Services) для нахождения разнообразной информации об имеющихся в сети ресурсах и службах, в том числе и о соответствии имени сервера его сетевому адресу. Так как служба NDS поддерживается только серверами с версией NetWare 4.x и выше, то для работы с версиями NetWare 3.x маршрутизаторы распознают SAP-пакеты по номеру их сокета и передают их на все порты, имитируя широковещательные рассылки локальной сети, на что тратится значительная часть пропускной способности медленных глобальных линий. Кроме того, такая «псевдошироковещательность» сводит на нет изоляцию сетей от некорректных SAP-пакетов.

В последних версиях своей операционной системы NetWare компания Novell значительно модифицировала свой стек для того, чтобы он мог более эффективно использоваться в крупных составных сетях.

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

Кроме того, постоянное повышение быстродействия глобальных служб уменьшает недостатки оригинальных протоколов стека IPX/SPX, что позволяет некоторым обозревателям говорить об успешной работе операционной системы NetWare в глобальных сетях и без указанных нововведений.

Источник

Сетевое программирование для разработчиков игр. Часть 2: прием и передача пакетов данных

Прием и передача пакетов данных

Введение

Привет, меня зовут Гленн Фидлер и я приветствую вас в своей второй статье из цикла “Сетевое программирование для разработчиков игр”.

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

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

А сейчас я собираюсь рассказать вам, как на практике использовать UDP для отправки и приема пакетов.

BSD сокеты

В большинстве современных ОС имеется какая-нибудь реализация сокетов, основанная на BSD сокетах (сокетах Беркли).

Сокеты BSD оперируют простыми функциями, такими, как “socket”, “bind”, “sendto” и “recvfrom”. Конечно, вы можете обращаться к этим функциями напрямую, но в таком случае ваш код будет зависим от платформы, так как их реализации в разных ОС могут немного отличаться.

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

Особенности разных ОС

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

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

В UNIX системах функции работы с сокетами входят в стандартные системные библиотеки, поэтому никакие сторонние библиотеки нам в этом случае не нужны. Однако в Windows для этих целей нам нужно подключить библиотеку winsock.

Вот небольшая хитрость, как можно это сделать без изменения проекта или makefile’а:

Мне нравится этот прием потому, что я ленивый. Вы, конечно, можете подключить библиотеку в проект или в makefile.

Инициализация сокетов

В большинстве unix-like операционных систем (включая macosx) не требуется никаких особых действий для инициализации функционала работы с сокетами, но в Windows нужно сначала сделать пару па — нужно вызвать функцию “WSAStartup” перед использованием любых функций работы с сокетами, а после окончания работы — вызвать “WSACleanup”.

Давайте добавим две новые функции:

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

Создаем сокет

Теперь мы можем создать UDP сокет. Это делается так:

Далее мы должны привязать сокет к определенному номеру порта (к примеру, 30000). У каждого сокета должен быть свой уникальный порт, так как, когда приходит новый пакет, номер порта определяет, какому сокету его передать. Не используйте номера портов меньшие, чем 1024 — они зарезервированы системой.

Если вам все равно, какой номер порта использовать для сокета, вы можете просто передать в функцию “0”, и тогда система сама выделит вам какой-нибудь незанятый порт.

Теперь наш сокет готов для передачи и приема пакетов данных.

Но что это за таинственная функция “htons” вызывается в коде? Это просто небольшая вспомогательная функция, которая переводит порядок следования байтов в 16-битном целом числе — из текущего (little- или big-endian) в big-endian, который используется при сетевом взаимодействии. Ее нужно вызывать каждый раз, когда вы используете целые числа при работе с сокетами напрямую.

Вы встретите функцию “htons” и ее 32-битного двойника — “htonl” в этой статье еще несколько раз, так что будьте внимательны.

Перевод сокета в неблокирующий режим

По умолчанию сокеты находится в так называемом “блокирующем режиме”. Это означает, что если вы попытаетесь прочитать из него данные с помощью “recvfrom”, функция не вернет значение, пока не сокет не получит пакет с данными, которые можно прочитать. Такое поведение нам совсем не подходит. Игры — это приложения, работающие в реальном времени, со скоростью от 30 до 60 кадров в секунду, и игра не может просто остановиться и ждать, пока не придет пакет с данными!

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

Перевести сокет в неблокирующий режим можно следующим образом:

Как вы можете видеть, в Windows нет функции “fcntl”, поэтому вместе нее мы используем “ioctlsocket”.

Отправка пакетов

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

Переслать пакет на определенный адрес можно следующим образом:

Обратите внимание — возвращаемое функцией “sendto” значение показывает только, был ли пакет успешно отправлен с локального компьютера. Но оно не показывает, был ли пакет принят адресатом! В UDP нет средств для определения, дошел ли пакет по назначению или нет.

В коде, приведенном выше, мы передаем структуру “sockaddr_in” в качестве адреса назначения. Как нам получить эту структуру?

Допустим, мы хотим отправить пакет по адресу 207.45.186.98:30000.

Запишем адрес в следующей форме:

И нужно сделать еще пару преобразований, чтобы привести его к форме, которую понимает “sendto”:

Как видно, сначала мы объединяем числа a, b, c, d (которые лежат в диапазоне [0, 255]) в одно целое число, в котором каждый байт — это одно из исходных чисел. Затем мы инициализируем структуру “sockaddr_in” нашими адресом назначения и портом, при этом не забыв конвертировать порядок байтов с помощью функций “htonl” и “htons”.

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

Прием пакетов

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

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

Код приема пакетов в цикле:

Пакеты, размер которых больше, чем размер буфера приема, будут просто втихую удалены из очереди. Так что, если вы используете буфер размером 256 байтов, как в примере выше, и кто-то присылает вам пакет в 300 байт, он будет отброшен. Вы не получите просто первые 256 байтов из пакета.

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

Закрытие сокета

На большинстве unix-like систем, сокеты представляют собой файловые дескрипторы, поэтому для того, чтобы закрыть сокеты после использования, можно использовать стандартную функцию “close”. Однако, Windows, как всегда, выделяется, и в ней нам нужно использовать “closesocket”.

Так держать, Windows!

Класс сокета

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

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

Поэтому мы сделаем класс-обертку “Socket” для всех этих операций. Также мы создадим класс “Address”, чтобы было проще работать с IP адресами. Он позволит не проводить все манипуляции с “sockaddr_in” каждый раз, когда мы захотим отправить или принять пакет.

Итак, наш класс Socket:

Использовать их для приема и передачи нужно следующим образом:

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

Заключение

Теперь у нас есть независимый от платформы инструмент для отправки и према UDP пакетов.

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

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

> Node 30000
> Node 30001
> Node 30002
И т.д…

Каждый из узлов будет пересылать пакеты всем остальным узлам, образуя нечто вроде мини peer-to-peer системы.

Я разрабатывал эту программу на MacOSX, но она должна компилироваться на любой unix-like ОС и на Windows, однако если вам для этого потребуется делать какие-либо доработки, сообщите мне.

Источник

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

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