2.Протокол ipx
В процессе решения поставленной задачи Вам предлагается использовать протокол IPX, который предоставляет возможность программам, запущенным на рабочих станциях, обмениваться пакетами данных на уровне датаграмм, т.е. без подтверждения.
Протокол - это набор правил и процедур, регулирующих порядок осуществления некоторой связи. Это правила и технические процедуры, позволяющие нескольким компьютерам при объединении в сеть общаться друг с другом.
Для того чтобы научиться составлять программы, которые могут передавать данные по сети с использованием протокола IРХ, Вам необходимо знать структуру пакета IРХ и научиться пользоваться функциями IРХ, реализованными в рамках сетевой оболочки рабочей станции.
Формат пакета IРХ. Формат пакета состоит из следующих полей:
Checksum - контрольная сумма (2 байта);
Lenght - общая длина пакета (2 байта);
TransportControl - счетчик пройденных маршрутизаторов (1 байт);
PacketType - тип пакета (1 байт);
DestNetwork - номер сети получателя пакета (4 байта);
DestNode - адрес станции получателя (6 байт);
DestSocket - сокет программы получателя (2 байта);
SourceNetwork - номер сети отправителя пакета (4 байта);
SourceNode - адрес станции отправителя (6 байт);
SourceCocket - сокет программы отправителя (2 байта);
Data - передаваемые данные (0-546 байт);
Пакет можно разделить на две части - заголовок и передаваемые данные. Все поля, представленные выше, кроме последнего, представляют собой заголовок пакета.
Заголовок пакета выполняет ту же роль, что и конверт обычного письма - там располагается адрес назначения, обратный адрес и некоторая служебная информация.
Поле Checksum предназначено для хранения контрольной суммы передаваемых пакетов. При формировании собственных пакетов Вам не придется заботиться о содержимом этого поля, так как проверка данных по контрольной сумме выполняется драйвером сетевого адаптера.
Поле Length определяет общий размер пакета вместе с заголовком. Длина заголовка фиксирована и составляет 30 байт. Размер передаваемых в поле Data данных может составлять от 0 до 546 байт, следовательно, в поле Length в зависимости от размера поля Data могут находиться значения от 30 до 576 байт. Если длина поля Data равна нулю, пакет состоит из одного заголовка. При формировании собственных пакетов Вам не надо проставлять длину пакета в поле Length, протокол IPX сделает это сам (вернее, программный модуль, отвечающий за реализацию протокола IPX, вычислит длину пакета на основании длины поля Data).
Поле TransportControl служит счетчиком маршрутизаторов, которые проходит пакет на своем пути от передающей станции к принимающей. Каждый раз, когда пакет проходит через маршрутизатор, значение этого счетчика увеличивается на единицу. Перед передачей пакета IPX сбрасывает содержимое этого поля в нуль. Так как IPX сам следит за содержимым этого поля, при формировании собственных пакетов Вам не надо изменять или устанавливать это поле в какое-либо состояние.
Поле PacketType определяет тип передаваемого пакета. Программа, которая передает пакеты средствами IPX, должна установить в поле PacketType значение 4.
Поле DestNetwork определяет номер сети, в которую передается пакет. При формировании собственного пакета вам необходимо заполнить это четырехбайтовое поле.
Поле DestNode определяет адрес рабочей станции, которой предназначен пакет. Вам необходимо определить все шесть байт этого поля.
Поле DestSocket предназначено для адресации программы, запущенной на рабочей станции, которая должна принять пакет. При формировании пакета Вам необходимо заполнить это поле.
Поля SourceNetwork, SourceNode и SourceSocket содержат соответственно номер сети, из которой посылается пакет, адрес передающей станции и сокет программы, передающей пакет.
Поле Data в пакете IPX содержит передаваемые данные. Если длина поля Data равна нулю, пакет состоит из одного заголовка. Такой пакет может использоваться программой, например, для подтверждения приема пакета с данными.
Для формирования заголовка пакета можно воспользоваться, например, следующей структурой:
struct IPX_HEADER
{
unsigned int Checksun;
unsigned int Length;
unsigned char TransportControl;
unsigned char PacketType;
unsigned char DestNetwork[4];
unsigned char DestNode[6];
unsigned int DestSocket;
unsigned char SourceNetwork[4];
unsigned char SourceNode[6];
unsigned int SourceSocket;
};
Работа с драйвером IPX. Первое, что должна сделать программа, желающая работать в сети с протоколом IPX, - проверить, установлен ли драйвер соответствующего протокола. Затем необходимо получить адрес вызова этого драйвера - точку входа API (Application Programm Interface - интерфейс для приложений). В дальнейшем программа вызывает драйвер при помощи команды межсегментного вызова процедуры по адресу точки входа API драйвера IPX.
Для того чтобы проверить, загружен ли драйвер IPX, необходимо загрузить в регистр АХ значение 7A00h и вызвать мультиплексное прерывание INT 2Fh.
Если после возврата из прерывания в регистре AL будет значение FFh, драйвер IPX загружен. Адрес точки входа для вызова API драйвера при этом будет находиться в регистровой паре ES:DI.
Если же содержимое регистра AL после возврата из прерывания INT 2Fh будет отлично от FFh, драйвер IPX не загружен.
Примечание. При реализации на языке "Си" (Borland C++, версия 2.0 или 3.0) для вызова прерывания используйте процедуру int86x.
Если программа реализуется на языке "Си", то необходимо указатель на точку входа описать не как указатель на переменную какого-либо типа, а как указатель на процедуру. Например, void far (*ipxspx_drv_entry)(void). Получить указатель можно с помощью функции - MK_FP().
Пример.
Функция ipx_init позволяет определить загружен ли драйвер IPX и точку входа API драйвера. Следует особо указать, что точку входа необходимо описать как глобальный указатель на функцию перед основной функцией main(). Например, void far (*ipxspx_entry)(void);
int ipx_init (void)
{
union REGS inregs, outregs;
struct SREGS segregs;
void far *a;
int s;
inregs.x.ax = 0x7a00;
int86x(0x2f, &inregs, &outregs, &segregs);
s = outregs.h.al;
if (s == 0xff)
{
printf("Есть драйвер !!!!");
ipxspx_entry = MK_FP (segregs.es, outregs.x.di);
return(0);
}
else
{
printf("Нет драйвера!!!!");
return(-1);
}
}
Для вызова API в регистр ВХ необходимо загрузить код выполняемой функции. Значения, загружаемые в другие регистры, зависят от выполняемой функции.
