Хосту Е неизвестна внутренняя топология сети 190.50.0.0. Он просто отсылает дейтаграмму шлюзу R2. Только R2 и другие хосты внутри сети определяют существование подсетей и маршруты доступа к ним.
Этот протокол обеспечивает логический коммуникационный канал между источником и получателем без предварительного установления связи. Протокол не обеспечивает надежной связи, поэтому приложения сами должны позаботиться об этом.
Из-за минимальной функциональности протокол требует меньших накладных расходов по сравнению с TCP.
Структура заголовка UDP представлена ниже.
0 - 15 |
16 - 31 |
Source port |
Destination Port |
Length |
Checksum |
Data |
|
Длина дейтаграммы не может быть меньше 8 байтов.
Если контрольная сумма используется, то она вычисляется по следующим полям IP-заголовка:
Protocol;
Source address;
Destination address
Примеры использования протокола UDP:
Синхронизация времени;
Удаленное копирование;
Удаленный вызов процедур.
Протокол используется для обмена данными в тех случаях, когда потеря отдельного сообщения не слишком сильно влияет на работу системы в целом.
ТСР – протокол, поддерживающий надежную передачу данных с предварительным установлением связи между источником и получателем.
ТСР характеризуется следующими особенностями:
Перед фактической передачей данных необходимо установление связи, т. е. запрос и подтверждение на возможность передачи данных. После обмена данными сеанс должен быть явно завершен;
Доставка информации является надежной, т. е. нет дублирования, пропадания и нарушения очередности пакетов.
TCP-канал - это двунаправленный поток данных между соответствующими объектами обмена – источником и получателем. Данные передаются в виде пакетов различной длины, называемых сегментами.
Формат ТСР сегмента представлен ниже.
0 – 3 |
4 - 7 |
8 - 11 |
12 - 15 |
16 - 19 |
20 - 23 |
24 - 27 |
28 – 31 |
Source port |
Destination port |
||||||
Sequence number |
|||||||
Acknowledgement number |
|||||||
Offset |
Reserved |
Flags |
Window |
||||
Checksum |
Urgent pointer |
||||||
Options |
Padding |
||||||
Data |
|||||||
Формат TCP-сегмента
Положение каждого сегмента в потоке фиксируется порядковым номером (Sequence number). Сегмент также содержит номер подтверждения (Acknowledgement number), определяющий номер первого неподтвержденного байта в потоке.
Поле Window определяет количество байтов, которые получатель готов принять, начиная с байта, номер которого определен как Acknowledgement number.
Поле Offset указывает на начало данных в сегменте. Поле необходимо т.к. заголовок может иметь переменную длину.
Поле Flags содержит 6 управляющих битов:
URG – экстренные данные
ACK – в заголовке есть подтверждение
PSH – немедленная передача данных
RST – уничтожение канала
SYN – управляющее сообщение
FIN – прекращение передачи
Поле Checksum – контрольная сумма
Поле Urgent pointer – указатель на экстренные данные (при установленном флаге URG).
Поле Options – дополнительные параметры.
Поле Padding – выравнивающее до 32 бит поле.
TCP-сеанс состоит из трех этапов.
Этап 1 – установление соединения
Одна из сторон, становящаяся клиентом, посылает другой стороне – серверу – запрос
Если сервер готов общаться с клиентом, то он создает канал (создает необходимые структуры данных) и посылает подтверждение;
Клиент тоже создает канал (необходимые структуры данных) и посылает ответ.
На этом этап создания канала завершается.
Этап 2. Обмен данными
После создания канала стороны обмениваются данными в дуплексном режиме.
Логически данные представляются в виде последовательности байтов, каждый из которых адресуется порядковым номером.
Когда требуется немедленная передача данных, протокол верхнего уровня устанавливает флаг PSH.
Ошибочные данные повторяются. Ошибки обнаруживаются за счет использования контрольных сумм.
Если данные доставлены без ошибок, получатель подтверждает это сегментом ACK.
Если отправитель не получил подтверждения в течение некоторого времени, он повторно посылает данные.
Этап 3. Разъединение
Любая из сторон может завершить передачу. Другая сторона подтверждает завершение, но может продолжать передачу по уже одностороннему каналу. Когда эта вторая сторона завершит передачу, а первая пошлет подтверждение, тогда канал полностью закрывается.
Примеры состояний TCP-канала
готовность сервера к приему запросов;
клиент послал запрос на соединение;
сервер получил запрос и отослал подтверждение;
канал установлен;
сторона послала запрос на разъединение;
сторона приняла запрос и отправила на него подтверждение.
В реальных ОС сетевые протоколы поддерживаются с помощью API, драйверов протоколов, а также драйверов устройств сетевых адаптеров.
Соотношение между перечисленными объектами и 7-уровневой архитектурой выглядит следующим образом.
7 |
Сетевое приложение |
6 |
Библиотеки сетевых API |
5 |
|
4 |
Драйверы протоколов TCP/IP |
3 |
|
2 |
Библиотека драйверов NDIS (network driver interface specification) |
1 |
Сетевые адаптеры |
К сетевым API относятся следующие средства:
Почтовые ящики – MailSlots;
Именованные каналы – Named Pipe;
Удаленные вызовы процедур – RPC;
Сокеты – Sockets.
Почтовые ящики обеспечивают механизм ненадежной односторонней передачи сообщений.
Почтовый ящик создается вызовом:
MsFile = CreateMailslot("\\\\.\\mailslot\\mymailslot",
0,
MAILSLOT_WAIT_FOREVER,
NULL);
Машина, на которой создан почтовый ящик, становится сервером и может только принимать сообщения.
Клиент открывает почтовый ящик вызовом:
MsFile = CreateFile("\\\\pc_name\\mailslot\\mymailslot",
GENERIC_READ|GENERIC_WRITE,
FILE_SHARE_READ|FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL);
После открытия почтового ящика клиент может посылать сообщения с помощью вызова:
WriteFile(MsFile, S, S.GetLength(), &NumberOfBytesWritten, NULL);
Сервер может читать сообщения из почтового ящика с помощью вызова:
ReadFile(MsFile, buffer, sizeof(buffer), &NumberOfBytesRead, NULL);
Если данных нет, например, они еще не передавались, то процесс, вызвавший операцию ReadFile(), приостановит свое выполнение. Это далеко не всегда приемлемо.
Чтобы преодолеть указанный недостаток, можно пойти двумя путями:
Выполнять операцию ReadFile() в отдельном потоке;
Использовать технологии асинхронного ввода-вывода.
Организация асинхронного ввода-вывода – это задача, которая решается в разных ситуациях по-разному.
Применительно к Mailslot для асинхронного чтения данных может быть использована функция:
BOOL GetMailslotInfo(
HANDLE hMailslot, // mailslot handle
LPDWORD lpMaxMessageSize, // maximum message size
LPDWORD lpNextSize, // size of next message
LPDWORD lpMessageCount, // number of messages
LPDWORD lpReadTimeout // read time-out interval
);
Получив из этой функции число сообщений (должно быть больше нуля), можно вызывать функцию ReadFile() с параметром:
ReadFile(MsFile, buffer, NextSize ,&NumberOfBytesRead, NULL);
После завершения работы приложения закрывают почтовый ящик с помощью вызова:
CloseHandle(MsFile);
Здесь приведены только основные вызовы для работы с почтовым ящиком. В реально действующих приложениях все несколько сложнее.
Пример потока, выполняющего операцию чтения из почтового ящика, представлен ниже:
UINT ReadThread(LPVOID pParam)
{
DWORD cbMessage, cMessage, cbRead;