Электронная библиотека книг Александра Фролова и Григория Фролова.
Shop2You.ru Создайте свой интернет-магазин
Библиотека
Братьев
Фроловых

Локальные сети персональных компьютеров. Использование протоколов IPX, SPX, NETBIOS

© Александр Фролов, Григорий Фролов
Том 4, М.: Диалог-МИФИ, 1993, 160 стр.

[Назад] [Содеожание] [Дальше]

2.3. Основные функции API драйвера IPX

API драйвера протокола IPX состоит из примерно дюжины функций, предназначенных для выполнения операций с сокетами, сетевыми адресами, для приема и передачи пакетов и некоторых других операций. В этом разделе мы кратко рассмотрим состав и назначение основных функций IPX.

2.3.1. Функции для работы с сокетами

В этом разделе мы опишем функции IPXOpenSocket и IPXCloseSocket, предназначенные для получения и освобождения сокетов.

IPXOpenSocket

На входе: BX = 00h.
AL = Тип сокета:
00h - короткоживущий;
FFh - долгоживущий.
DX = Запрашиваемый номер сокета или 0000h, если требуется получить динамический номер сокета.
Примечание. Байты номера сокета находятся в перевернутом виде.
На выходе: AL = Код завершения:
00h - сокет открыт;
FFh - этот сокет уже был открыт раньше;
FEh - переполнилась таблица сокетов.
DX = Присвоенный номер сокета.

Перед началом передачи пакетов программа должна получить свой идентификатор - сокет. Функция IPXOpenSocket как раз и предназначена для получения сокета.

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

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

Если вы не используете динамическое распределение сокетов и задаете свой номер сокета, используйте значения в диапазоне от 4000h до 8000h или получите персональный зарегистрированный сокет у фирмы Novell.

По умолчанию при загрузке оболочки рабочей станции вам доступно максимально 20 сокетов. При соответствующей настройке сетевой оболочки вы можете увеличить это значение до 150.

IPXCloseSocket

На входе: BX = 01h.
DX = Номер закрываемого сокета.
На выходе: Регистры не используются.

Функция закрывает заданный в регистре DX сокет, короткоживущий или долгоживущий.

Если с закрываемым сокетом связаны ECB, находящиеся в обработке (в состоянии ожидания завершения приема или передачи), указанные ECB освобождаются, а ожидающие завершения операции отменяются. При этом в поле InUse для таких ECB проставляется нулевое значение, а в поле CCode - значение FCh, означающее, что операция была отменена.

Для отмененных ECB программы ESR не вызываются.

Функцию IPXCloseSocket нельзя вызывать из программы ESR.

2.3.2. Функции для работы с сетевыми адресами

IPXGetLocalTaget

На входе: BX

=

02h.
ES:SI

=

Указатель на буфер длиной 12 байт, содержащий полный сетевой адрес станции, на которую будет послан пакет.
ES:DI

=

Указатель на буфер длиной 6 байт, в который будет записан непосредственный адрес, т. е. адрес той станции, которой будет передан пакет. Это может быть адрес моста.
На выходе: AL

=

Код завершения:
00h - непосредственный адрес был успешно вычислен;
FAh - непосредственный адрес вычислить невозмож- но, так как к указанной станции нет ни одного пути доступа по сети.
CX

=

Время пересылки пакета до станции назначения (только если AL равен нулю) в тиках системного таймера. Тики таймера следуют с периодом примерно 1/18 секунды.

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

Так как станция-получатель может находиться в другой сети, прежде чем достигнуть цели, пакет может пройти один или несколько мостов. Поле непосредственного адреса ImmAddress блока ECB должно содержать либо адрес станции назначения (если передача происходит в пределах одной сети), либо адрес моста (если пакет предназначен для рабочей станции, расположенной в другой сети). Используя указанный в буфере размером 12 байт полный сетевой адрес, состоящий из номера сети, адреса станции в сети и сокета приложения, функция IPXGetLocalTaget вычисляет непосредственный адрес, т. е. адрес той станции в данной сети, которая получит передаваемый пакет.

Формат полного адреса представлен на рис. 4.

Рис. 4. Формат полного адреса

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

struct NET_ADDRESS {
        unsigned char Network[4];
        unsigned char Node[6];
        unsigned char Socket[2];
};



В поле Network указывается номер сети, в которой расположена станция, принимающая пакет.

Поле Node должно содержать адрес станции в сети с номером, заданным содержимым поля Network. Если пакет должны принять все станции, находящиеся в сети Network, в поле Node необходимо записать адрес FFFFFFFFFFFFh.

Поле Socket адресует конкретную программу, работающую на станции с заданным адресом.

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

IPXGetInternetworkAddress

На входе: BX

=

09h.
ES:DI

=

Указатель на буфер длиной 10 байт; в него будет записан адрес станции, на которой работает данная программа. Адрес состоит из номера сети Network и адреса станции в сети Node.
На выходе: Регистры не используются.

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

Формат буфера аналогичен представленному на рис. 4, за исключением того, что в буфер не записывается сокет. Считается, что сокет программа знает, так как она его открывала.

2.3.3. Прием и передача пакетов

IPXListenForPacket

На входе: BX = 04h.
ES:DI = Указатель на заполненный блок ECB. Необходимо заполнить поля:
ESRAddress;
Socket;
FragmentCnt;
указатели на буферы фрагментов Address;
размеры фрагментов Size.
На выходе: Регистры не используются.

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

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

Сразу после вызова функции IPXListenForPackets в поле InUse блока ECB устанавливается значение FEh, которое означает, что для данного блока ECB ожидается прием пакета. Как мы уже говорили, программа может ожидать одновременно много пакетов.

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

После прихода пакета в поле CCode использованного блока ECB драйвер IPX записывает код результата приема пакета, а в поле ImmAddress - непосредственный адрес станции, из которой пришел пакет. Если пакет пришел из другой сети, в этом поле будет стоять адрес моста (адрес моста в той сети, где находится принимающая станция).

Затем в поле InUse блока ECB проставляется нулевое значение и вызыва-
ется программа ESR, если ее адрес был задан перед вызовом функции IPXListenForPackets.

После приема пакета в поле CCode могут находиться следующие значения:

00 пакет был принят без ошибок;
FFh указанный в ECB сокет не был предварительно открыт программой;
FDh переполнение пакета: либо поле количества фрагментов в пакете FragmentCnt равно нулю, либо буферы, описанные дескрипторами фрагментов, имеют недостаточный размер для записи принятого пакета;
FCh запрос на прием данного пакета был отменен специальной функцией драйвера IPX.

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

Если запрос на прием пакета был отменен специальной функцией или в результате выполнения функции IPXCloseSoket, поле InUse блока ECB устанавливается в нулевое значение, однако программа ESR, даже если ее адрес был задан, не вызывается. В поле CCode проставляется значение FCh.

IPXSendPacket

На входе: BX = 03h.
ES:DI = Указатель на заполненный блок ECB. Необходимо заполнить поля:
ESRAddress;
Socket;
ImmAddress;
FragmentCnt;
указатели на буферы фрагментов Address;
размеры фрагментов Size.В заголовке пакета IPX необходимо заполнить поля:
PacketType;
DestNetwork;
DestNode;
DestSocket.
На выходе: Регистры не используются.

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

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

Пакет будет передан в станцию, адрес которой указан в поле ImmAddress. Если в этом поле указан адрес моста, пакет будет передан через мост в другую сеть. Разумеется, что вы должны кроме непосредственного адреса задать еще и номер сети адресата, а также адрес станции в этой сети. Для вычисления непосредственного адреса (который надо будет записать в поле ImmAddress) можно воспользоваться описанной выше функцией IPXGetLocalTaget.

Сразу после вызова функции IPXSendPacket в поле InUse блока ECB устанавливается значение FFh. После завершения процесса передачи пакета поле InUse принимает значение 00h. Результат выполнения передачи пакета можно узнать, если проанализировать поле CCode блока ECB:

00 пакет был передан без ошибок (что, кстати, не означает, что пакет был доставлен по назначению и успешно принят станцией-адресатом, так как протокол IPX не обеспечивает гарантированной доставки пакетов);
FFh пакет невозможно передать физически из-за неисправности в сетевом адаптере или в сети;
FEh пакет невозможно доставить по назначению, так как станция с указанным адресом не существует или неисправна;
FDh сбойный пакет: либо имеет длину меньше 30 байт, либо первый фрагмент пакета по размеру меньше размера стандартного заголовка пакета IPX, либо поле количества фрагментов в пакете FragmentCnt равно нулю;
FCh запрос на передачу данного пакета был отменен специальной функцией драйвера IPX.

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

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

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

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

IPXRelinquishControl

На входе: BX = 0Ah.
На выходе: Регистры не используются.

Если ваша программа не использует ESR, она, очевидно, должна в цикле опрашивать поле InUse блока ECB, для которого выполняется ожидание завершения процесса приема или передачи пакета. Однако для правильной работы драйвера IPX в цикл ожидания необходимо вставлять вызов функции IPXRelinquishControl. Эта функция выделяет драйверу IPX процессорное время, необходимое для его правильной работы.

[Назад] [Содеожание] [Дальше]