7. ПЕРЕДАЧА И ПРИЕМ СООБЩЕНИЙ7.2. Определение режима приема сообщений 7.3. Установка режима приема сообщений 7.4. Передача сообщений пользователям 7.5. Прием сообщений В этой главе мы рассмотрим службу передачи сообщений, которая имеется в операционной системе Novell NetWare. Эта служба позволяет организовать передачу коротких сообщений между рабочими станциями с использованием ресурсов файл-сервера. Например, утилита SEND операционной системы Novell NetWare передает сообщения именно с помощью описанных в этой главе средств. Мы расскажем вам не о всех возможностях системы передачи сообщений, а только о самой интересной, на наш взгляд, - возможности передачи сообщений от одной рабочей станции на другие и на файл-сервер. Об организации передачи сообщений через каналы (Pipes) вы можете узнать из документации, поставляющейся вместе с библиотекой функций NetWare C Interface. Работа системы передачи сообщений основана на том, что файл-сервер для каждой подключенной к нему рабочей станции создает буфер размером 55 байт. Этот буфер используется для временного хранения сообщения, предназначенного для рабочей станции. Помимо сообщений от рабочих станций файл-сервер может передавать свои собственные сообщения, например сообщение о завершении своей работы. Для передачи сообщения на другие рабочие станции программа должна использовать функцию SendBroadcastMessage(). Можно передать сообщение и на консоль файл-сервера, для этого используется функция BroadcastToConsole(). 7.1. Режимы приема сообщенийЧто происходит, когда рабочая станция принимает сообщение? Это зависит от того, кто послал сообщение (другой пользователь или файл-сервер), а также от режима приема сообщений, установленном на рабочей станции. Станция может принимать сообщения в четырех режимах:
Для установки режима используется функция SetBroadcastMode(), текущий режим можно определить с помощью функции GetBroadcastMode(). Если сообщение не отображается автоматически, программа, запущенная на рабочей станции, может извлечь его из буфера при помощи функции GetBroadcastMessage(). Например, при работе в графическом режиме ваша программа должна уметь получать сообщения и отображать их, так как сетевая оболочка отображает сообщения только в текстовом режиме работы видеоадаптера. 7.2. Определение режима приема сообщенийПервое, что должна сделать программа, обрабатывающая сообщения, это определить текущий режим приема сообщений. Для этого она должна вызвать функцию GetBroadcastMode(): BYTE GetBroadcastMode(void); Функция возвращает значение в диапазона от 0 до 3, соответствующее текущему режиму приема сообщений. Вместо функции GetBroadcastMode() для определения текущего режима приема сообщений вы можете воспользоваться функцией DEh прерывания INT 21h:
7.3. Установка режима приема сообщенийПеред завершением работы ваша программа должна восстановить режим обработки сообщений (если задачей программы не является изменение этого режима). Для восстановления режима воспользуйтесь функцией SetBroadcastMode(): void SetBroadcastMode(BYTE BroadcastMode); Параметр BroadcastMode определяет новый режим приема сообщений. Вместо функции SetBroadcastMode() для определения текущего режима приема сообщений вы можете воспользоваться функцией DEh прерывания INT 21h:
7.4. Передача сообщений пользователямДля передачи сообщения другим пользователям предназначена функция SendBroadcastMessage(): int SendBroadcastMessage(char *Message, WORD *ConnectionList, BYTE *ResultList, WORD ConnectionCount); Параметр Message задает адрес текстовой строки, содержащей сообщение. Размер этой строки не должен превышать 56 байт (включая двоичный ноль, закрывающий строку). Параметр ConnectionList - указатель на массив слов, содержащий номера каналов, используемых файл-сервером для связи с рабочими станциями. Размер этого массива определяется параметром ConnectionCount. Параметр ResultList - массив байт, в котором для каждой станции отражается результат посылки сообщения:
Функция возвращает 0 при успешном завершении или код ошибки:
Вместо функции SendBroadcastMessage() можно использовать функцию E1h прерывания INT 21h:
Буфер запроса: 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. Посылка сообщения станциям // Файл msgsend\msgsend.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., 1993\n"); 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] != '\0') { printf("%s\n", ObjectName); // Записываем номер канала в массив ConnectionList[j++] = i; ConnectionCount += 1; } } // Посылаем сообщение обнаруженным пользователям SendBroadcastMessage(argv[1], ConnectionList, ResultList, ConnectionCount); } 7.5. Прием сообщенийДля приема сообщений предназначена функция GetBroadcastMessage(): int GetBroadcastMessage(char *MessageBuffer); Параметр определяет адрес буфера, в который будет записано принятое сообщение. Размер буфера должен составлять не менее 56 байт. Функция возвращает 0 при успешном завершении или код ошибки:
Если в буфере нет сообщений, в первый байт буфера будет записано нулевое значение. Вместо функции GetBroadcastMessage() можно использовать функцию E1h прерывания INT 21h:
Буфер запроса: struct REQUEST { WORD PacketLength; // размер пакета запроса BYTE Function; // должно быть равно 1 }; Буфер ответа: struct REPLAY { WORD PacketLength; // размер пакета BYTE MessageLength; // длина сообщения BYTE Message[MessageLength]; // сообщение }; 7.5.1. Программа MSGRCVПрограмма MSGRCV (листинг 29) изменяет текущий режим приема сообщений, блокируя автоматическую выдачу сетевой оболочкой приходящих сообщений в нижней строке экрана. Программа сама принимает эти сообщения и сама выводит их в стандартный поток вывода. Перед завершением работы восстанавливается старый режим приема сообщений. // =================================================== // Листинг 29. Прием сообщений // Файл msgrcv\msgrcv.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., 1993\n"); // Проверяем присутствие сетевой оболочки 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] != '\0') { printf(">>> %s\n", MessageBuffer); } // Если оператор нажал на любую клавишу, // завершаем работу программы if(kbhit()) break; } // Восстанавливаем старый режим приема сообщений SetBroadcastMode(OldBroadcastMode); } |