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

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

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

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

2.5. Пример c использованием ESR

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

Когда ESR получает управление, регистры процессора содержат следующие значения:

AL идентификатор вызывающего процесса:
FFh - программа ESR вызвана драйвером IPX;
00h - программа ESR вызвана планировщиком асинхронных событий AES (будет описан позже);
ES:SI адрес блока ECB, связанного с данной ESR.

Содержимое всех регистров, кроме SS и SP, а также флаги процессора записаны в стек программы.

Если ESR будет обращаться к глобальным переменным программы, необходимо правильно загрузить регистр DS. Непосредственно перед вызовом ESR прерывания запрещаются. Функция ESR не возвращает никакого значения и должна завершать свою работу командой дальнего возврата RETF. Перед возвратом управления прерывания должны быть запрещены.

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

Наша программа-ESR (листинг 8) выполняет простую задачу - записывает адрес связанного с ней блока ECB в глобальную переменную completed_ecb_ptr, которая сбрасывается в главной программе перед ожиданием приема пакета. Программа-клиент (листинг 7), ожидая прихода пакета, выполняет какие-либо действия (в нашем случае она просто вводит символы с клавиатуры и выводит их на экран) и периодически опрашивает глобальную переменную. Как только пакет будет принят, в эту переменную будет записан отличный от нуля адрес блока ECB.

// ===================================================
// Листинг 7. Клиент IPX
// Файл ipxclien.c
//
// (C) A. Frolov, 1993
// ===================================================

#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
#include <mem.h>
#include <string.h>
#include <dos.h>
#include "ipx.h"

// Максимальный размер буфера данных

#define BUFFER_SIZE 512

extern struct ECB far * completed_ecb_ptr;
extern void far         ipxspx_esr(void);

void main(void) {

// Будем работать с сокетом 0x4567

        static unsigned Socket = 0x4567;

// ECB для приема и передачи пакетов

        struct ECB RxECB, TxECB;

// Заголовки принимаемых и передаваемых пакетов

        struct IPX_HEADER RxHeader, TxHeader;

// Буферы для принимаемых и передаваемых данных

        unsigned char RxBuffer[BUFFER_SIZE];
        unsigned char TxBuffer[BUFFER_SIZE];

        printf("\n*Клиент IPX*, (C) Фролов А., 1993\n\n");

// Проверяем наличие драйвера IPX и определяем
// адрес точки входа его API

        if(ipx_init() != 0xff) {
                printf("IPX не загружен!\n"); exit(-1);
        }

// Открываем сокет, на котором будем принимать и передавать пакеты

        if(IPXOpenSocket(SHORT_LIVED, &Socket)) {
                printf("Ошибка при открытии сокета\n");
                exit(-1);
        };

// Подготавливаем ECB для передачи пакета

        memset(&TxECB, 0, sizeof(TxECB));

        TxECB.Socket            = IntSwap(Socket);
        TxECB.FragmentCnt       = 2;
        TxECB.Packet[0].Address = &TxHeader;
        TxECB.Packet[0].Size    = sizeof(TxHeader);
        TxECB.Packet[1].Address = TxBuffer;
        TxECB.Packet[1].Size    = BUFFER_SIZE;

// Пакет предназначен всем станциям данной сети

        memset(TxECB.ImmAddress, 0xff, 6);

// Подготавливаем заголовок пакета

        TxHeader.PacketType = 4;
        memset(TxHeader.DestNetwork, 0, 4);
        memset(TxHeader.DestNode, 0xff, 6);
        TxHeader.DestSocket = IntSwap(Socket);

// Записываем передаваемые данные

        strcpy(TxBuffer, "ESR/CLIENT *DEMO*");

// Передаем пакет всем станциям в данной сети

        IPXSendPacket(&TxECB);

        completed_ecb_ptr = (unsigned long)0;

// Подготавливаем ECB для приема пакета от сервера

        memset(&RxECB, 0, sizeof(RxECB));
        RxECB.Socket            = IntSwap(Socket);
        RxECB.FragmentCnt       = 2;
        RxECB.Packet[0].Address = &RxHeader;
        RxECB.Packet[0].Size    = sizeof(RxHeader);
        RxECB.Packet[1].Address = RxBuffer;
        RxECB.Packet[1].Size    = BUFFER_SIZE;
        RxECB.ESRAddress        = ipxspx_esr;

        IPXListenForPacket(&RxECB);

        printf("Ожидание ответа от сервера\n");
        printf("Нажимайте любые клавиши\n");
        printf("Для отмены нажмите клавишу <ESC>\n");

// Ожидаем прихода ответа от сервера

        while(completed_ecb_ptr == NULL) {
                if( getche() == 27) {
                        IPXCloseSocket(&Socket);
                        exit(0);
                }
        }
        if(RxECB.CCode == 0) {
                printf("\nПринят ответ от сервера '%s'\n", RxBuffer);
        }

// Закрываем сокет

        IPXCloseSocket(&Socket);
        exit(0);
}



В листинге 8 приведен текст программы ESR, составленный на языке ассемблера. Программа загружает регистр DS адресом сегмента данных программы, затем записывает в глобальную переменную completed_ecb_ptr содержимое регистров ES:SI.

; ===================================================
; Листинг 8. Программа ESR
; Файл esr.asm
;
; (C) A. Frolov, 1992
; ===================================================

.286
.MODEL SMALL

.DATA

        _completed_ecb_ptr dd 0

.CODE

        PUBLIC   _ipxspx_esr
        PUBLIC  _completed_ecb_ptr

_ipxspx_esr PROC FAR

                mov     ax, DGROUP
                mov     ds, ax

                mov     word ptr _completed_ecb_ptr+2, es
                mov     word ptr _completed_ecb_ptr, si

                retf
_ipxspx_esr ENDP

end



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