Локальные сети персональных компьютеров. Использование протоколов IPX, SPX, NETBIOS© Александр Фролов, Григорий ФроловТом 4, М.: Диалог-МИФИ, 1993, 160 стр. 2.5. Пример c использованием ESRВ предыдущем примере при ожидании пакета мы опрашивали в цикле поле InUse блока ECB. Однако более эффективным является использование программы ESR. Эта программа получает управление тогда, когда пакет принят и поле InUse установлено в ноль. Когда 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
|

