1. Протоколы обмена данными в ОС NetWare
2. Система понятий и управляющие блоки протоколов
3. Использование функций протоколов SPX и IPX
3.1. Общая последовательность взаимодействия по
протоколу IPX
3.2. IPXInitialize
3.3. IPXOpenSocket
3.4. IPXGetInternetworkAddress
3.5. IPXGetDataAddress
3.6. IPXGetLocalTarget
3.7. IPXSendPacket
3.8. IPXListenForPacket
3.9. IPXRelinquishControl
3.10. IPXGetIntervalMaker
3.11. IPXCancelEvent
3.12. IPXDisconnectFromTarget
3.13. IPXCloseSocket
При создании многопользовательских программных систем,
функционирующих в среде локальных сетей, возникает необходимость
организации обмена между процессами, функционирующими на различных узлах.
Это может быть связано не обязательно с ведением разделяемых баз данных,
но и с таким потребностями, как синхронизация процессов, организация
работы с многопользовательским ресурсом и т.д.
Для этого, исходя из возможностей ОС NetWare, можно
выделить 3 способа коммуникации:
1. Файловый.В этом случае процессы обмениваются
информацией через файл, расположенный на сервере. Одна станция пишет в
файл, другая (другие) читают информацию, помещенную туда. Этот метод прост
в реализации, но не эффективен в случае его использования для
синхронизации процессов и некоторых других приложений.
2. С использованием сервисов NetWare.В сетевой
операционной системе реализована поддержка механизмов синхронизации
процессов на рабочих станциях (семафоры и логические записи), а также
обмена информацией - Broadcast и Pipe сообщения. Доступ к ним можно
получить через обращения к редиректору NetWare - NETx.COM(EXE).
Программисты, пишушие на языке C, для этого могут использовать пакет
фирмы Novell "NetWare C-Interface for DOS".
3. С использованием функций низкоуровневых протоколов,
на которых обменивается информацией сама сетевая операционная система.
К числу этих протоколов можно отнести протоколы IPX и SPX. Эти протоколы
могут позволить организовать связь между прикладными процессами на различных
узлах сети наиболее эффективным образом с точки зрения скорости обмена
и нагрузки на сетевую аппаратуру. Для того чтобы воспользоваться услугами
протоколов IPX-SPX, совсем не обязательно наличие в локальной,
сети файлового сервера и запуска программ редиректоров на рабочих
станциях(NETx.COM). Эти протоколы поддерживаются программой-драйвером
сетевой платы IPX.COM, либо пакетными драйверами.
Программирование обмена с использованием низкоуровневых
протоколов создает определенные трудности для программистов даже с
достаточно высоким уровнем квалификации. Проблемы здесь связаны с точным
пониманием логики работы персонального компьютера, а также с явно
недостаточно полным описанием функций работы с протоколами, предоставленным
фирмой Novell с пакетом "NetWare C-Interface for DOS".
Протокол IPX(Internetwork Packet Exchange -
Межсетевой Обмен Пакетов) принадлежит к классу так называемых датаграммных
протоколов транспортного уровня, т.е. "послал-забыл". То есть он не дает
гарантий, что пакет был правильно принят адресатом. Но это не означает, что
пакет может быть утерян на пути от источника к адресату аппаратурой
сети. Если адрес указан верно, и работающая станция-адресат включена,
то пакет с вероятностью, равной надежности аппаратуры сети, будет ею
получен в буфер сетевой платы. По собственному опыту работы авторы
использовали этот протокол для реализации обмена в системе проведения
электронного аукциона и программе сетевой пересылки файлов, фрагменты
которой приведены в качестве примера.
Протокол SPX(Sequenced Packet Exchange -
Последовательный обмен пакетов) можно отнести к классу протоколов
виртуального соединения или гарантированной доставки. Посылающий процесс
получает подтверждение о получении пакета принимающей стороной автоматически.
Это во многом упрощает программирование систем, в которых четко требуется
реализация механизма подтверждения о приеме пакета. В принципе протокол
SPX является протоколом более высокого уровня, чем IPX,поскольку он
полностью реализован на его примитивах. Схема протокола SPX заведомо
исключает получение соединений типа один со многими, т.е. процесс может
установить обмен через одно соединение только с одним процессом в другом
узле.
На протоколе SPX реализована сама ОС NetWare и все
сопровождающие ее многочисленные продукты фирмы Novell - серверы печати,
коммуникационные серверы, шлюзы и т.д.
В настоящем издании, во многом опираясь на руководство
к пакету "NetWare C-Interface for DOS", мы попытались изложить описание
коммуникационного сервиса NetWare в несколько иной - более практической
транскрипции, попытавшись уменьшить трудность его первоначального
понимания с помощью более развитой системы примеров.
Тем, кто не занимался серьезно программированием с
использованием протоколов транспортного уровня, первоначально достаточно
сложно уяснить некоторые понятия, используемые в документации к пакету
"NetWare C-Interface for DOS". Важнейшим из них является понятие сетевого
адреса.
В протоколах IPX-SPX сетевой адрес состоит из трех
полей, Первое поле (4 байта) содержит номер сети. Он задается при генерации
файлового сервера или межсетевого моста. Если в локальной сети сервер (мост)
выключен или отсутствует, то в этом поле должны стоять нули. Следующее
поле (6 байт) содержит адрес сетевой платы станции. В платах ArcNet
этот адрес задается вручную на этапе сборки сети, в Ethernet он, как
правило, прожигается на заводе. Последнее поле (2 байта) содержит номер
сокета (англ.socket-гнездо, розетка). Оно используется для задания
адреса процесса внутри узла. В "NetWare C-Interface for DOS" он описан
ввиде struct IPXAddress в файле NXT.H :
"Старший-младший" определяет порядок следования байтов.
Нормальный порядок следования байт "младший-старший", поэтому при работе
с этими полями нужно быть особенно внимательным и для извлечения информации
из них необходимо использовать функции типа IntSwap().
Типы BYTE и WORD определены в NXT.H соответственно как
unsigned char и unsigned int.
После получения сигнала от сетевой платы о получении
или успешной отсылки пакета, IPX.COM вызывает связанную с этим гнездом
пользовательскую программу обработки события. И уже после этого данные
могут быть обработаны прикладной программой.
Под событием понимают одноразовую операцию, связанную
с приемом (отсылкой) одного пакета. Все события группируются вокруг тиков
таймера компьютера (если не использовать IPXRelinqushControl см. ниже).
Взамодействие прикладной программы с IPX.COM
происходит через блок обработки события (Event Control Block), сокращенно
"ECB". Он представляет непрерывный участок памяти длиной 48 байтов.
В терминах "NetWare C-Interface for DOS" это struct ECB. Она определена
в файле NXT.H и состоит из следующих полей:
В приведенных выше комментариях, символ "s" (Send)
обозначает поля, которые должна установить прикладная программа при
использовании Блока ECB для отправки пакета. Буква "r" (Receive)
обозначает поля, которые должна установить прикладная программа при
использовании Блока ECB для получения пакета. Символ "t" (Time) обозначает
поля, которые должна установить прикладная программа при использовании
Блока ECB для планирования события по часам (во времени). "Старший-младший"
определяет порядок следования байтов. Нормальный порядок следования байт
"младший-старший", поэтому при работе с этими полями нужно быть особенно
внимательным и для извлечения информации из них необходимо использовать
функции типа IntSwap().
Протокол IPX-SPX использует полe linkAddress для
внутренних целей.
Поле ESRAddress (адрес ESR - Event SubRoutine)
содержит адрес определяемой прикладной программой Подпрограммы. При вызове
этой программы регистры ES:SI содержат адрес вызвавшего ее блока обработки
события. Эту подпрограмму нужно писать по всем правилам написания программы
обработки прерывания - восстанавливать сегмент данных программы,
аккуратно работать с функциями, использующими обращения к DOS. Например,
использование функции printf() в данной процедуре приводит к зависанию.
IPX-SPX записывает в поле inUseFlag (флаг
использования) текущее состояние события. Прикладная программа может
задействовать это поле для определения факта завершения события.
Поле completionCode (код завершения) содержит код
завершения для события, который обозначает, был ли пакет отправлен успешно,
или пакет имеет неправильный формат и т.п.
Поле socketNumber (номер гнезда) определяет
отправляющий или получающий сокет, к которому подстыковывается данный ECB.
Поля IPXWorkspace (рабочая область IPX) и
driverWorkspace (рабочая область драйвера) используются для внутренних
целей протоколом и драйвером сетевой платы. Эти поля нельзя изменять.
Протокол SPX возвращает в этом поле идентификационный номер соединения SPX.
Поле immediateAddress (непосредственный адрес)
содержит адрес узла, которому отправляется пакет, или узла, от которого он
получается. Если пакет не получен от узла и не отправлен узлу в местной сети,
то этим адресом будет адрес межсетевого моста в местной сети. Для
заполнения этого поля следует использовать функцию IPXGetLocalTarget.
Поле fragmentCount обозначает количество буферов
(не более двух), из которых будет построен исходящий (отправляемый) пакет,
или на которые будет разбит принимаемый пакет. Прикладная программа дает
список дескрипторов фрагментов в конце Блока ECB, с буфером адреса и
размера, обозначенным посредством поля fragmentCount. Первый фрагмент
обязательно в начале должен содержать место под протокольный заголовок
пакета (struct IPXHeader или struct SPXHeader). Суммарная длина двух
фрагментов не должна превышать 576 байтов.
Заголовок пакета IPX - IPXHeader определен в
файле NXT.H и состоит из следующих полей:
CheckSum - предназначено для контрольной суммы
содержимого пакета и всегда устанавливается IPX как 0xFFFF. Прикладной прог-
рамме данное поле устанавливать не надо.
Length - содержит длину полного пакета IPX
(от 30 до 576 байт) состоящего из заголовка пакета IPX ( 30 байт) и
порции данных (от 0 до 546 байт). IPX.COM сам задает значение
этого поля как FragmentDescriptor[0].Size + FragmentDescriptor[2].Size
при отправке пакета. Обратите внимание на "старший-младший" - длина
принятого пакета = IntSwap(Length).
transportControl - используется межсетевыми
мостами NetWare для определения количества мостов или маршрутов, которые
прошел пакет. Далее 16-го моста пакеты не проходят. IPX устанавливает
это поле как ноль перед тем, как отправлять пакет.
packetType - определяет тип пакета. Значительная
часть типов используется Novell для своих внутренних нужд и рекомендует
программистам устанавливать его значение в 0 или 4. Для пакета SPX IPX.COM в
это автоматически прописывает 5.
destination - содержит сетевой адрес станции
получателя и номер сокета на ней и имеет тип IPXAddress. При отправке
пакета прикладная программа должна установить это поле. Для передачи
широковещательного сообщения в байты соответствующие номеру узла
необходимо записать 0xFFFFFFFFFFFF.
 source - в это поле IPX.COM заполняет сетевой
адрес узла, отсылающего пакет и номер сокета.
Протокол SPX имеет семь дополнительных полей в своем
заголовке. Его длинна 42 байта. Он определен в NXT.H как struct SPXHeader
Протокол SPX устанавливает все поля в заголовке SPX
в IPX.COM, кроме поля destination и dataStreamType.
Поле connectionControl управляет двунаправленным
потоком данных по соединению SPX.
Поле dataStreamType обозначает тип данных,
включенных в пакет. Величины с (0x00) до (0xFD) определяются пользователем и
игнорируются протоколом SPX. Величина (0xFE) обозначает пакет конца
соединения. Когда пользователь делает вызов SPXTerminateConnection(),
SPX генерирует пакет 0xFE. Этот пакет затем отправляется партнеру по
соединению как последний пакет в соединении. Величина (0xFF) обозначает
квитированный пакет конца соединения. SPX генерирует пакет
End-of-Connection-Acknowledgement (Конец-Соединения-Квитирование)
автоматически. Он помечается как системный пакет и не доставляется
пользователям-партнерам. Поэтому величины (0xFE) и (0xFF) не следует
использовать.
Поля sourceConectionID и destConectionID
определяют номер соединения, который SPX присваивает соединению
отправляющим узлом и узлом-адресатом, соответственно.
Поле sequenceNumber содержит количество пакетов,
отправленных в одном направлении по соединению. Каждая сторона соединения
ведет свой собственный подсчет.
Поле acknowledgeNumber хранит номер следующего
пакета, который ожидает получить соединение SPX.
Поле allocationNumber обозначает число свободных
блоков управления событием узла-партнера для приема пакетов. SPX будет
отправлять пакеты, пока локальное sequenceNumber не станет равно
allocationNumber удаленного партнера.
Величины в трех последних полях пошагово увеличиваются
от 0000h до FFFFh, а затем снова переводятся на нули - поля являются
счетчиками по модулю 0xFFFF+1.
В описании функций из раздела "Коммуникационные услуги"
пакета "NetWare C-Interface for DOS" их разбили на три группы:
Реально для написания программы на IPX-SPX могут
потребоваться вызовы функций всех трех групп. Поэтому мы отказались от
стандартного способа изложения их описания и предлагаем здесь описание
функций по способам их использования в том порядке в каком они реально
могут встретится в прикладной программе использующей протоколы IPX-SPX.
За исключением IPXSheduleIPXEvent, вам будут
необходимы для написания программы обмена по IPX все функции асинхронного
планировщика событий. Чтобы далее к ней не возвращаться, скажем, что
IPXSheduleIPXEvent не используется сама по себе при пересылке
информации. Она может быть использована как способ унификации обработки
событий в вашей программе.
В самом начале работы прикладная программа должна
проверить наличие IPX в оперативной памяти и получить адрес входа для
интерфейса IPX, вызвав функцию IPXInitialize. Данная функция должна
быть вызвана до вызова любой функции IPX.
Перед тем, как начать обмен пакетами с помощью IPX,
прикладные программы на обеих сетевых станциях должны открыть сокеты
функцией IPXOpenSocket. Номер сокета, открытого на станции А должен
быть известен прикладной программе на станции Б и наоборот.
Номера сокетов определить просто - достаточно установить
соглашение между прикладными программами по использованию их номеров гнезд.
Обе станции должны знать сетевой адрес (адрес сети и
узла) друг друга. Но автоматически его определить невозможно. Как правило
известен только пользовательский идентификатор сетевой станции. Для
получения по нему сетевого адреса другой станции можно воспользоваться
функциями GetObjectConnectionNumbers (см. Connection Service
NetWare C-Interface for DOS) или IPXGetInternetworkAddress,
вызвав их в начале программы. Но необходимо помнить, что NetWare позволяет
использовать один и тот же идентификатор пользователя на нескольких станциях
одновременно. В этом случае обычно используется первое значение из
полученного списка. Остальные значения игнорируются.
По окончании передачи и приема пакетов, прикладные
программы на обеих станциях должны закрыть гнезда, вызвав функцию
IPXCloseSocket.
После того, как прикладная программа на станции А
открыла гнездо и определила адрес сети, узла и номер гнезда на станции Б,
а станция Б получила такую же информацию о станции А, они готовы к приему и
передаче пакетов. Для отправки пакета используется функция
IPXSendPacket, а для приема - IPXListenForPacket. При каждом
вызове IPXSendPacket ей должно передаваться дополнительное поле -
immediateAddress.
Поле immediateAddress содержит адрес узла,
которому отправляется пакет, или узла, от которого он получается. Если пакет
не получен от узла и не отправлен узлу в местной сети, то этим адресом будет
адрес межсетевого моста в местной сети. Для получения информации для этого
поля может быть использована функция IPXGetLocalTarget.
IPX не переходит в состояние ожидания окончания отправки
или получения пакета, эти операции только инициализируются. Реальная отправка
и прием происходят в фоновом режиме. Ход этих операций можно отслеживать
двумя способами: либо прикладная программа периодически проверяет
признак завершения операции inUseFlag, либо передает IPX адрес
подпрограммы (ESRAddress), которая будет выполнена при завершении
события.
Данная функция обращаясь к мультиплексному прерыванию
с кодом 0x7A детектирует наличие IPX.COM в памяти и получает адрес точки
входа в IPX (IPXLocation). IPXInitialize() обязательно должна
присутствовать перед первым вызовом любой другой функции. В случае отсутствия
IPX.COM в памяти (на бридже или файл-сервере это будет протокол, связанный
с драйвером сетевой платы) функция возвращает значение 240 (0xF0).
Ее можно использовать следующим образом:
Все ниже перечисленные функции, за исключением
IPXGetDataAddress, являются непосредственно функциями протокола
IPX-SPX.
Обращения к ним формируются как вызов функции
(*IPXLocation)() с соответствующим кодом :
Данная функция открывает сокет(гнездо IPX).
Прикладная программа должна использовать эту функцию
для открытия сокета перед тем, как получить пакет.
Параметр socketNumber содержит номер открываемого
сокета. Передача величины 0000h в это поле позволяет IPX открыть
доступные гнезда по своему выбору в диапазоне от 0x4000 до 0x5000.
Это называется ДИНАМИЧЕСКИМ открытием гнезда.
Если данная функция возвращает код завершения (0x00),
то гнездо было успешно открыто, как и ожидалось. Если код завершения
равен (0xFE), то таблица сокетов уже заполнена.
Если функция возвращает код завершения (0xFF), то
указанный сокет уже открыт.
Параметр socketType определяет, как долго сокет
должен оставаться открытым. Если только программа не собирается завершаться
и оставаться резидентной, тип гнезда может быть временным - "краткосрочным"
(0x00). Гнезда, открытые как временные (краткосрочные) - SHORT_LIVED -
автоматически закрываются при завершении программы (если загружен редиректор
NetWare NETx.COM) и все соответственные события, ожидающие на этом
гнезде, отменяются. Если прикладная программа открывает гнездо как
постоянное ("долгосрочное") - LONG_LIVED - (0xFF), она должна гарантировать,
что подпрограмма ESR (подпрограмма обслуживания события) будет
доступной даже после завершения этой прикладной программы. В противном
случае рабочая станция может зависнуть, если подпрограмма ESR
(подпрограмма обслуживания события) вызывается IPX после того, как она стала
недоступной.
По умолчанию, IPX поддерживает до 20 открытых гнезд на рабочей
станции. Максимальное количество одновременно открытых гнезд для рабочей
станции может достигать 150; конфигурация производится в файле
SHELL.CFG.
Данная функция возвращает адрес сети и узла
запрашивающей рабочей станции.
Параметр networkAddress заполняется 10-байтовым
адресом узла в сети. Байты 0-3 = номер сети Байты 4-9 = номер узла
Пример:
Данная функция возвращает адрес данных в буфере, на
который указывает параметр Address.
Параметр data является указателем на элемент данных,
чей адрес будет возвращен в параметре address. Адрес возвращается в порядке
сегмент-смещение. (То есть, адрес = смещение, адрес + 2 = сегмент).
Эта функция не являет собой обращение к какой либо
функции протокола IPX-SPX. Она главным образом необходима для того чтобы
не путаться в вычислении адреса буффера данных в различных моделях памяти
компиляторов языка Си.
Пример:
Данная функция необходима при установлении связи по
протоколу IPX, особенно в том случае, когда связываемые узлы находятся в
разных сегментах сети. Она помещает в поле immediateAddress (непосредственный
адрес) блока ECB адрес ближайшего узла, до которого будет идти пересылка.
Если узлы находятся в одном сегменте сети, то это будет непосредственный
узел адресата, в противном случае это будет адрес сетевого
бриджа (файлового сервера).
Параметр immediateAddress получает указатель
на 6-байтовое поле блока ECB.
Параметр transportTime получает подсчет времени
(в шагах таймера системы, равных приблизительно 1/18 части секунды),
которое занимает передача 576-байтового пакета от исходного узла к
узлу-адресату. Так как возвращаемая величина является только приближенным
подсчетом, фактическое время передачи может отличаться от данного,
в зависимости от трафика сети и размера пакета. Если у вас отправитель
и адресат связаны скоростными каналами локальных сетей, это значение как
правило равно 1. Если же между ними лежит асинхронный бридж с телефонными
линями связи, вы можете через это поле определять значения таймаутов в вашей
программе.
В случае успешного нахождения сети получателя функция
выполняется достаточно быстро и возвращает значение 0 (0x00) SUCCESSFUL.
В противном случае она как бы на время подвешивает машину и возвращает
250 (0xFA) NO_LOCAL_TARGET_IDENTIFIED . Данная функция передает IPX
межсетевой адрес узла-получателя. IPX возвращает вычисленное время передачи
пакета и либо адрес узла для узла-адресата, либо адрес узла для локального
моста, который будет использовать IPX для маршрутизации пакета к
узлу-адресату.
Функция IPXGetLocalTarget может быть использована
с адресами получателей используя широковещательные величины (все 0xFF) в
поле node (узел).
Когда IPX получает пакет, он записывает адрес узла -
отправителя в поле immediateAddress получающего блока ECB. Шесть байт
immediateAddress - это номер локального узла-отправителя, а не номер
исходного узла. Номер локального узла-отправителя - это номер вызывающей
рабочей станции. Следовательно, когда прикладная программа начинает обмен
пакетами с прикладной программой на другом узле, любая из этих прикладных
программ может использовать поле immediateAddress из получающего
блока ECB для извлечения номера местного узла-адресата, вместо того,
чтобы повторно вызывать функцию IPXGetLocalTarget.
Результатом работы IPXGetLocalTarget на станции
"Отправитель" будет адрес immediateAddress_1.
На станции "Получатель" после приема пакета поле
immediateAddress в ECB будет содержать адрес immediateAddress_N.
Пример :
Данная функция инициализирует отправку пакета IPX.
Функция IPXSendPacket передает IPX адрес блока ECB
для отправки пакета IPX. Эта функция возвращает управление вызывающей
прикладной программе, не дожидаясь окончания процесса отправки. С этого
момента IPX пытается отправить пакет. Прикладная программа может продолжить
свою работу, проверяя окончание процесса отправки либо по значению поля
inUseFlag в ECB, либо ожидая вызова процедуры, адрес которой должен
быть указан в поле ESRAddress в ECB.
Перед тем, как вызвать эту функцию, прикладная программа
должна инициализировать следующие поля блока ECB :
Если с данным ECB связывается некоторая процедура
обработки события, то ее адрес должен быть занесен в поле ESRAddress
(адрес подпрограммы ESR). Если никакой подпрограммы не вызывается, поле
ESRAddress должно содержать NULL.
Прикладная программа должна также подготовить заголовок
IPX соответствующего пакета посредством заполнения полей packetType и
destination (адресат). Затем функция передает блок ECB драйверам
коммуникации сети для начала операции отправки.
Несмотря на то, что socketNumber в Блоке ECB имеет
значение (IPX использует его как номер исходного узла в заголовке пакета),
гнездо НЕ НУЖНО открывать для выполнения операции отправки.
Поле immediateAddress в Блоке ECB может быть
установлено при помощи функции IPXGetLocalTarget.
Сначала IPX устанавливает поле блока ECB inUseFlag
как (0xFF), - это обозначает, что блок ECB отправляет пакет. После попытки
отправить пакет, IPX устанавливает поле completionCode блока ECB до
соответствующей величины и устанавливает поле inUseFlag как (0x00)
(AVAILIABLE_FOR_USE, и вызывает подпрограмму ESR (подпрограмму обслуживания
события), на которую указывает поле ESRAddress.
Ниже приводятся возможные величины для поля
completionCode блока ECB:
Более подробную информацию по кодам возврата вы можете
получить из документации на пакет программ "NetWare C-Interface for DOS"
Код завершения (0x00) обозначает, что пакет был успешно
отправлен, но не гарантирует, что он был успешно получен узлом-адресатом.
Например, носитель может потерять или повредить (засорить) пакет, или
же сокет-адресат может оказаться закрытым или не ждущим сигнала (не
"слушающим"). IPX не сообщает ничего отправляющему узлу, если возникают
подобные проблемы.
Код завершения (0xFE) обозначает, что пакет не может быть
доставлен. Блок ECB возвращает этот код завершения в одном из двух случаев:
Прикладная процесс может посылать или широковещетельно
отправлять пакет IPX в любой узел в интерсети, включая узел-отправитель.
Пакеты, отправленные к сокетам, которые находятся в том же узле, что и
сам прикладной процесс, называются "внутриузловыми" пакетами.
Пример:
Данная функция готовит IPX к получению пакета IPX.
Функция IPXListenForPacket передает IPX адрес
блока ECB для получения пакета IPX. Эта функция затем возвращает управление
вызывающей прикладной программе. В это время IPX ожидает сигнала ("слушает")
и пытается получить пакет.
Перед тем, как вызвать эту функцию, прикладная
программа должна открыть гнездо и инициализировать поля блока ECB
ESRAddress, socketNumber, immediateAddress,
fragmentCount и fragmentDescriptor. Если никакой подпрограммы
не вызывается, поле ESRAddress должно содержать NULL.
Сначала IPX устанавливает поле Блока ECB inUseFlag
как (0xFF), - это обозначает, что Блок ECB (Блок контроля события) ожидает
получения пакета. IPX также прибавляет Блок ECB к буферной области (пулу)
Блоков ECB, ждущих сигнала от пакетов IPX в одном и том же сокете. IPX
не налагает ограничений на количество Блоков ECB, которые могут параллельно
ждать сигнала в одном сокете.
Когда IPX обнаруживает прибывающий пакет, он использует
один из ожидающих сигнала Блоков ECB для получения этого пакета. Ожидающие
сигнала Блоки ECB НЕ заполняются в том порядке, в каком они поступают
в IPX. IPX записывает соответствующую величину в поле completionCode
(код завершения) выбранного Блока ECB и помещает адрес узла в поле
immediateAddress Блока ECB. Эта величина в поле
immediateAddress обозначает либо отправляющий узел (если отправляющий
узел находится в том же сегменте сети), либо локальный мост, который
переправил пакет (если отправляющий узел не находится в локальной сети).
Наконец, IPX устанавливает поле inUseFlag (флаг
использования) блока ECB как 00h (AVAILIABLE_FOR_USE - Доступен для
использования), и вызывает подпрограмму ESR (подпрограмму обслуживания
события), на которую указывает поле ESRAddress (адрес подпрограммы
ESR) Блока ECB (если это возможно).
Ниже приводятся возможные величины для кода завершения
Блока ECB (Блока контроля события):
Пример:
Данная функция передает в IPX управление центральным
процессором рабочей станции.
Прикладная программа может использовать данную функцию
для временной передачи управления в IPX, чтобы во то время, когда она,
например, ожидает ввода с клавиатуры, могла выполняться обработка принятых
пакетов. Иначе запуск коммуникационного драйвера IPX будет происходить
на очередном тике внутреннего таймера машины.
Пример ее использования смотрите в примере к функции
IPXListenForSocket.
Данная функция получает от IPX значение временного
маркера.
Маркер интервала является величиной в диапазоне от 0
до 65535 (0x0000 и 0xFFFF). Каждый интервал представляет собой один шаг
таймера IBM PC, который приблизительно равен 1/18 части секунды.
Прикладная программа может использовать данную функцию
для измерения времени (интервала) между двумя событиями. Для того, чтобы
сделать это, прикладная программа выполняет два вызова данной функции,
каждый из которых возвращает маркер интервала, соответствующий времени
события. Затем прикладная программа вычитает первый маркер интервала
из второго. Разность представляет собой временной интервал между двумя
событиями (в тиках таймера). Этот результат остается точным, даже если
внутренний маркер переходит через ноль между первым и вторым событием.
Этот таймер не предназначен для использования с большими временными
интервалами (более одного часа), вследствие точности внутреннего маркера
(16 бит без знака).
Пример ее использования смотрите в примере к функции
IPXListenForSocket.
Данная функция отменяет событие, определенное
Блоком ECB.
Возвращаемые значения:
Данная функция отменяет ожидающее событие посредством
передачи IPX адреса ECB (Блока контроля события). Эта функция возвращает
код завершения при возвращении управления прикладной программе.
Блок ECB также может быть задействован под такие
события, как отправка или ожидание сигнала - для IPX, планирование или
перепланирование - для AES, или ожидание сигнала - для SPX. В этом случае
его поле inUseFlag устанавливается в ненулевое значение. И попытка его
повторного использования может привести к зависанию программы. Для того
чтобы освободить блок для использования под новое событие, необходимо
вызвать IPXCancelEvent. После этого поле inUseFlag установится в нулевое
значение.
Значения поля inUseFlag:
1. Протоколы обмена данными в ОС NetWare
BYTE network[4]; /* старший-младший */
BYTE node[6]; /* старший-младший */
WORD socket; /* старший-младший */
void far *linkAddress;
void (far *ESRAddress)(); /* sr t */
BYTE inUseFlag;
BYTE completionCode;
WORD socketNumber; /* sr,старший-младший */
BYTE IPXWorkspace[4]; /* N/A */
BYTE driverWorkspace[12]; /* N/A */
BYTE immediateAddress[6]; /* s, старший-младший */
WORD fragmentCount; /* sr, */
ECBFragment fragmentDescriptor[2];
WORD checkSum; /* старший-младший */
WORD length; /* старший-младший */
BYTE transportControl;
BYTE packetType;
IPXAddress destination;
IPXAddress source;
WORD checkSum;
WORD length; /* старший-младший */
BYTE transportControl;
BYTE packetType;
IPXAddress destination;
IPXAddress source;
BYTE connectionControl; /* флаги бит */
BYTE dataStreamType;
WORD sourceConnectionID; /* старший-младший */
WORD destConnectionID; /* старший-младший */
WORD sequenceNumber; /* старший-младший */
WORD acknowledgeNumber; /* старший-младший */
WORD allocationNumber; /* старший-младший */
3. Использование функций протоколов SPX и IPX.
BYTE IPXInitialize(void)
#include
IPXOpenSocket 0x00
IPXCloseSocket 0x01
IPXGetLocalTarget 0x02
IPXSendPacket 0x03
IPXListenForPacket 0x04
IPXSheduleEvent 0x05
IPXCancelEvent 0x06
IPXGetIntervalMaker 0x08
IPXGetInternetworkAddress 0x09
IPXRelinquishControl 0x0A
IPXDisconnectFromTarget 0x0B
SPXInitialize 0x10
SPXEstablishConnection 0x11
SPXListenForConnection 0x12
SPXTerminateConnection 0x13
SPXAbortConection 0x14
SPXGetConnectionStatus 0x15
SPXSendSequencedPacket 0x16
SPXListenForSequencedPacket 0x17
3.3. IPXOpenSocket
int IPXOpenSocket(BYTE *socketNum, BYTE socketType)
Возвращаемые значения:
0 (0x00) SUCCESSFUL Успешное выполнение
240 (0xF0) IPX_NOT_INSTALLED IPX не установлен
254 (0xFE) SOCKET_TABLE_FULL Таблица сокетов заполнена
245 (0xFF) SOCKET_ALREADY_OPEN Сокет уже открыт
Пример:
#include
void IPXGetInternetworkAddress(BYTE *networkAddress)
#include
void IPXGetDataAddress(char *data, WORD *address)
#include
int IPXGetLocalTarget(BYTE *networkAddress,
BYTE *immediateAddress, int *transportTime)
Параметр networkAddress содержит указатель на
12-байтовый адрес получателя в сети.
3.7. IPXSendPacket
void IPXSendPacket(ECB *eventControlBlock)
0 (0x00) SUCCESSFUL Успешное выполнение
252 (0xFC) REQUEST_CANCELLED Запрос отменен
253 (0xFD) BAD_PACKET Неправильный пакет
(Данный пакет не
имеет 30-байтового
заголовка пакета в качестве
первого фрагмента, или же
общая длина пакета превышает
576 байт)
254 (0xFE) PACKET_NOT_DELIVERABLE Пакет не может быть
доставлен
255 (0xFF) HARDWARE_FAILURE Сбой в аппаратуре
#include
void IPXListenForPacket(ECB *eventControlBlock)
0 (0x00) SUCCESSFUL Успешное выполнение
252 (0xFC) REQUEST_CANCELLED Запрос отменен
253 (0xFD) BAD_PACKET Неправильный пакет
255 (0xFF) SOCKET_NOT_OPEN Гнездо не открыто
#include
#include
3.9. IPXRelinquishControl
void IPXRelinquishControl(void);
3.10. IPXGetIntervalMaker
unsigned IPXGetIntervalMaker(void)
int IPXCancelEvent(ECB *eventControlBlock)
0 (0x00) SUCCESSFUL Успешное выполнение
249 (0xF9) ECB_CANNOT_BE_CANCELLED ECB не может быть от-
менен
252 (0xFC) EVENT_CANCELLED Событие отменено
255 (0xFF) ECB_NOT_IN_USE ECB не используется
Свободен
224 (0xE0) Временный индикатор AES
248 (0xF8) Критическая задержка
250 (0xFA) Обработка
251 (0xFB) Задержка (в обработке
после того, как произошло событие)
252 (0xFC) Асинхронный планировщик событий ожидает 253 (0xFD) Ожидание
254 (0xFE) Получение
255 (0xFF) Отправление
Пример:
#include