Untitled
7. ПЕРЕДАЧА И ПРИЕМ СООБЩЕНИЙ
7.1. Режимы приема сообщений
7.2. Определение режима приема сообщений
7.3. Установка режима приема сообщений
7.4. Передача сообщений пользователям
7.5. Прием сообщений
В этой главе мы рассмотрим службу передачи сообщений, которая
имеется в операционной системе Novell NetWare. Эта служба позволяет
организовать передачу коротких сообщений между рабочими станциями
с использованием ресурсов файл-сервера. Например, утилита SEND
операционной системы Novell NetWare передает сообщения именно
с помощью описанных в этой главе средств. Мы расскажем вам не
о всех возможностях системы передачи сообщений, а только о самой
интересной, на наш взгляд, - возможности передачи сообщений от
одной рабочей станции на другие и на файл-сервер. Об организации
передачи сообщений через каналы (Pipes) вы можете узнать из документации,
поставляющейся вместе с библиотекой функций NetWare C Interface.
Работа системы передачи сообщений основана на том, что файл-сервер
для каждой подключенной к нему рабочей станции создает буфер размером
55 байт. Этот буфер используется для временного хранения сообщения,
предназначенного для рабочей станции. Помимо сообщений от рабочих
станций файл-сервер может передавать свои собственные сообщения,
например сообщение о завершении своей работы.
Для передачи сообщения на другие рабочие станции программа должна
использовать функцию SendBroadcastMessage(). Можно передать сообщение
и на консоль файл-сервера, для этого используется функция BroadcastToConsole().
Что происходит, когда рабочая станция принимает сообщение? Это
зависит от того, кто послал сообщение (другой пользователь или
файл-сервер), а также от режима приема сообщений, установленном
на рабочей станции.
Станция может принимать сообщения в четырех режимах:
0 | Этот режим используется по умолчанию и устанавливается сразу после загрузки сетевой оболочки. Когда приходит сообщение, сетевая оболочка автоматически отображает сообщение в нижней строке экрана, но только в том случае, если установлен текстовый режим работы. В графических режимах работы сообщение не отображается
|
1 | В этом режиме файл-сервер запоминает в буфере приходящие от других пользователей сообщения, но сетевая оболочка отображает только сообщения, которые пришли от файл-сервера
|
2 | В этом режиме файл-сервер игнорирует сообщения от других пользователей, запоминая в буфере только сообщения от файл-сервера. Автоматический вывод сообщения на экран не выполняется
|
3 | Файл-сервер запоминает в буфере как сообщения, пришедшие от пользователей, так и сообщения файл-сервера. Автоматический вывод сообщения на экран не выполняется
|
Для установки режима используется функция SetBroadcastMode(),
текущий режим можно определить с помощью функции GetBroadcastMode().
Если сообщение не отображается автоматически, программа, запущенная
на рабочей станции, может извлечь его из буфера при помощи функции
GetBroadcastMessage(). Например, при работе в графическом режиме
ваша программа должна уметь получать сообщения и отображать их,
так как сетевая оболочка отображает сообщения только в текстовом
режиме работы видеоадаптера.
Первое, что должна сделать программа, обрабатывающая сообщения,
это определить текущий режим приема сообщений. Для этого она должна
вызвать функцию GetBroadcastMode():
BYTE GetBroadcastMode(void);
Функция возвращает значение в диапазона от 0 до 3, соответствующее
текущему режиму приема сообщений.
Вместо функции GetBroadcastMode() для определения текущего режима
приема сообщений вы можете воспользоваться функцией DEh прерывания
INT 21h:
На входе: | AH | =
| DEh; |
| DL | = |
В регистр DL необходимо загрузить значение 04h.
|
На выходе: | AL | =
| Номер текущего режима приема сообщений (0, 1, 2, 3).
|
Перед завершением работы ваша программа должна восстановить режим
обработки сообщений (если задачей программы не является изменение
этого режима). Для восстановления режима воспользуйтесь функцией
SetBroadcastMode():
void SetBroadcastMode(BYTE BroadcastMode);
Параметр BroadcastMode определяет новый режим приема сообщений.
Вместо функции SetBroadcastMode() для определения текущего режима
приема сообщений вы можете воспользоваться функцией DEh прерывания
INT 21h:
На входе: | AH | =
| DEh; |
| DL | = |
В регистр DL необходимо загрузить новое значение режима приема сообщений (0, 1, 2, 3).
|
На выходе: | |
| Регистры не используются. |
Для передачи сообщения другим пользователям предназначена функция
SendBroadcastMessage():
int SendBroadcastMessage(char *Message, WORD *ConnectionList,
BYTE *ResultList, WORD ConnectionCount);
Параметр Message задает адрес текстовой строки, содержащей сообщение.
Размер этой строки не должен превышать 56 байт (включая двоичный
ноль, закрывающий строку).
Параметр ConnectionList - указатель на массив слов, содержащий
номера каналов, используемых файл-сервером для связи с рабочими
станциями. Размер этого массива определяется параметром ConnectionCount.
Параметр ResultList - массив байт, в котором для каждой станции
отражается результат посылки сообщения:
0x00 | Сообщение передано успешно
|
0xFC | Сообщение не передано, так как буфер сообщения для данной станции уже содержит сообщение, которое еще не было принято станцией
|
0xFD | Соответствующий номер канала задан неправильно
|
0xFF | Станция заблокировала прием сообщения, установив соответствующий режим приема сообщений. Этот код ошибки может появиться и в том случае, если заданный номер канала не используется
|
Функция возвращает 0 при успешном завершении или код ошибки:
Код ошибки | Значение |
0xFE | Ошибка ввода/вывода или нехватка памяти на сервере
|
Вместо функции SendBroadcastMessage() можно использовать функцию
E1h прерывания INT 21h:
На входе: | AH | =
| E1h; |
| DS:SI | = |
Адрес буфера запроса; |
| ES:DI | = |
Адрес буфера ответа. |
На выходе: | AL | =
| Код ошибки или 0, если операция завершилась без ошибок.
|
Буфер запроса:
struct REQUEST {
WORD PacketLength; // размер пакета запроса
BYTE Function; // должно быть равно 0
BYTE ConnectionCount; // количество станций
BYTE ConnectionList[ConnectionCount];// список станций
BYTE MessageLength; // длина сообщения
BYTE Message[MessageLength]; // сообщение
};
Буфер ответа:
struct REPLAY {
WORD PacketLength; // размер пакета
BYTE ConnectionCount; // количество станций
BYTE ResultList[ConnectionCount];// результат
};
7.4.1. Программа MSGSEND
Программа MSGSEND (листинг 28) передает сообщение, заданное в
качестве параметра, всем пользователям, подключенным к файл-серверу.
Перед посылкой сообщения она с помощью функции BroadcastToConsole()
выводит текстовую строку на консоль файл-сервера и записывает
эту же строку в системный журнал net$log.msg, вызывая функцию
LogNetworkMessage().
Для получения списка пользователей программа использует функцию
GetConnectionInformation(). Эта функция возвращает информацию
о пользователе, подключенном к файл-серверу, по номеру канала.
Каналы нумеруются начиная с первого. Максимальное количество каналов
определяется версией операционной системы, его можно определить
при помощи функции GetServerInformation().
Сканируя все каналы, программа подготавливает массив номеров каналов
ConnectionList[] для функции SendBroadcastMessage(), которая и
выполняет рассылку сообщений.
// ===================================================
// Листинг 28. Посылка сообщения станциям
// Файл msgsendmsgsend.cpp
//
// (C) A. Frolov, 1993
// ===================================================
#include <stdlib.h>
#include <stdio.h>
#define WORD unsigned int
#define BYTE unsigned char
typedef struct {
char serverName[48];
BYTE netwareVersion;
BYTE netwareSubVersion;
WORD maxConnectionsSupported;
WORD connectionsInUse;
WORD maxVolumesSupported;
BYTE revisionLevel;
BYTE SFTLevel;
BYTE TTSLevel;
WORD peakConnectionsUsed;
BYTE accountingVersion;
BYTE VAPversion;
BYTE queingVersion;
BYTE printServerVersion;
BYTE virtualConsoleVersion;
BYTE securityRestrictionLevel;
BYTE internetBridgeSupport;
} FILE_SERV_INFO;
extern "C" int GetNetWareShellVersion(char *,char *, char *);
extern "C" int BroadcastToConsole(char *);
extern "C" int SendBroadcastMessage(char*, WORD*, BYTE*, WORD);
extern "C" int LogNetworkMessage(char*);
extern "C" void GetServerInformation(int, FILE_SERV_INFO*);
extern "C" int GetConnectionInformation(WORD, char *, WORD *,
long *, BYTE *);
void main(int argc, char *argv[]) {
char MajorVersion=0;
char MinorVersion=0;
char Revision=0;
long ObjectID;
char ObjectName[48];
WORD ObjectType;
BYTE LoginTime;
FILE_SERV_INFO ServerInfo;
int MaxUsers;
WORD ConnectionList[250];
BYTE ResultList[250];
WORD ConnectionCount;
printf("n*MSGSEND* (C) Frolov A., 1993n");
if(argc < 2) {
printf("Введите сообщение в качестве параметраn");
return;
}
// Проверяем присутствие сетевой оболочки
asm push si
GetNetWareShellVersion(&MajorVersion,
&MinorVersion, &Revision);
asm pop si
if(MajorVersion == 0) {
printf("nОболочка NetWare не загруженаn");
return;
}
// Выводим сообщение на консоль файл-сервера и
// записываем его в журнал
BroadcastToConsole("*MSGSEND* (C) Frolov A., 1993");
LogNetworkMessage("*MSGSEND* (C) Frolov A., 1993");
// Получаем информацию о сервере. Нас интересует
// в первую очередь максимальное количество пользователей,
// которые могут подключиться к файл-серверу
GetServerInformation(sizeof(ServerInfo), &ServerInfo);
// Запоминаем максимальное количество пользователей
MaxUsers = ServerInfo.maxConnectionsSupported;
printf("Сервер %s, версия на %d пользователейn",
ServerInfo.serverName, MaxUsers);
// Цикл посылки сообщений. Подсчитываем количество используемых
// каналов и для каждого канала заполняем массив ConnectionList[]
printf("nСообщение посылается пользователям:n");
ConnectionCount = 0;
for(int i=1, j=0; i <= MaxUsers; i++) {
// Получаем информацию о канале
GetConnectionInformation(i, ObjectName, &ObjectType,
&ObjectID, &LoginTime);
// Если есть имя объекта, выводим его на экран
if(ObjectName[0] != ' ') {
printf("%sn", ObjectName);
// Записываем номер канала в массив
ConnectionList[j++] = i;
ConnectionCount += 1;
}
}
// Посылаем сообщение обнаруженным пользователям
SendBroadcastMessage(argv[1],
ConnectionList, ResultList, ConnectionCount);
}
Для приема сообщений предназначена функция GetBroadcastMessage():
int GetBroadcastMessage(char *MessageBuffer);
Параметр определяет адрес буфера, в который будет записано принятое
сообщение. Размер буфера должен составлять не менее 56 байт.
Функция возвращает 0 при успешном завершении или код ошибки:
Код ошибки | Значение |
0xFC | Переполнение очереди сообщений
|
0xFE | Ошибка ввода/вывода или нехватка памяти на сервере
|
Если в буфере нет сообщений, в первый байт буфера будет записано
нулевое значение.
Вместо функции GetBroadcastMessage() можно использовать функцию
E1h прерывания INT 21h:
На входе: | AH | =
| E1h; |
| DS:SI | = |
Адрес буфера запроса; |
| ES:DI | = |
Адрес буфера ответа. |
На выходе: | AL | =
| Код ошибки или 0, если операция завершилась без ошибок.
|
Буфер запроса:
struct REQUEST {
WORD PacketLength; // размер пакета запроса
BYTE Function; // должно быть равно 1
};
Буфер ответа:
struct REPLAY {
WORD PacketLength; // размер пакета
BYTE MessageLength; // длина сообщения
BYTE Message[MessageLength]; // сообщение
};
7.5.1. Программа MSGRCV
Программа MSGRCV (листинг 29) изменяет текущий режим приема сообщений,
блокируя автоматическую выдачу сетевой оболочкой приходящих сообщений
в нижней строке экрана. Программа сама принимает эти сообщения
и сама выводит их в стандартный поток вывода.
Перед завершением работы восстанавливается старый режим приема
сообщений.
// ===================================================
// Листинг 29. Прием сообщений
// Файл msgrcvmsgrcv.cpp
//
// (C) A. Frolov, 1993
// ===================================================
#include <stdlib.h>
#include <stdio.h>
#include <conio.h>
#define WORD unsigned int
#define BYTE unsigned char
extern "C" int GetNetWareShellVersion(char *,char *, char *);
extern "C" int GetBroadcastMessage(char*);
extern "C" BYTE GetBroadcastMode(void);
extern "C" void SetBroadcastMode(BYTE);
void main(void) {
char MajorVersion=0;
char MinorVersion=0;
char Revision=0;
BYTE OldBroadcastMode;
char MessageBuffer[56];
int ccode;
printf("n*MSGRCV* (C) Frolov A., 1993n");
// Проверяем присутствие сетевой оболочки
asm push si
GetNetWareShellVersion(&MajorVersion,
&MinorVersion, &Revision);
asm pop si
if(MajorVersion == 0) {
printf("nОболочка NetWare не загруженаn");
return;
}
// Сохраняем старый режим приема сообщений
OldBroadcastMode = GetBroadcastMode();
// Устанавливаем режим, при котором сообщения от файл-сервера и поль-
// зователей записываются в буфер, но автоматически не отображаются
SetBroadcastMode(3);
// Ожидаем прихода сообщения
for(;;) {
// Извлекаем сообщение из буфера
ccode = GetBroadcastMessage(MessageBuffer);
if(ccode) break;
// Если сообщение есть в буфере, выводим его
if(MessageBuffer[0] != ' ') {
printf(">>> %sn", MessageBuffer);
}
// Если оператор нажал на любую клавишу,
// завершаем работу программы
if(kbhit()) break;
}
// Восстанавливаем старый режим приема сообщений
SetBroadcastMode(OldBroadcastMode);
}
|