Обмен информацией между программами в сети по почтовым каналам
Как реализовать обмен информацией между Вашими приложениями в сети? ОС Windows предлагает несколько технологий. Эта статья опишет один очень простой и надежный способ для Win9x/NT - MailSlots.
The CreateMailslot function creates a mailslot with the specified name and returns a handle that a mailslot server can use to perform operations on the mailslot. The mailslot is local to the computer that creates it. An error occurs if a mailslot with the specified name already exists.
Обмен текстовыми данными в локальной сети очень прост. Для этого необходимы функции:
CreateMailslot создание почтового канала; GetMailslotInfo определение наличия сообщения в канале; ReadFile чтение сообщения из канала, как из файла; WriteFile запись сообщения в канал, как в файл; Функции работы с почтовыми каналами присутствуют как в Windows 9x, так и в Windows NT.
Рассмотрим создание почтового канала (сервер).
//... создание канала с именем MailSlotName - по этому имени к нему // будут обращаться клиенты h := CreateMailSlot(PChar('\.mailslot' + MailSlotName), 0, MAILSLOT_WAIT_FOREVER,nil);
if h = INVALID_HANDLE_VALUE then begin raise Exception.Create('MailSlotServer: Ошибка создания канала !');
Отправка сообщений по почтовомуо каналу (клиенты).
if not GetMailSlotInfo(h,nil,DWORD(MsgNext),@MsgNumber,nil) then begin raise Exception.Create('TglMailSlotServer: Ошибка сбора информации!'); end;
if MsgNext <> MAILSLOT_NO_MESSAGE then begin beep; // чтение сообщения из канала и добавление в текст протокола if ReadFile(h,str,200,DWORD(read),nil) then MessageText := str else raise Exception.Create('TglMailSlotServer: Ошибка чтения сообщения !'); end;
Все очень просто. Теперь для удобства использования создадим два компонента - клиент и сервер
destructor TglMailSlotServer.Destroy; begin Timer.Free; // закрытие канала Close; inherited; end;
procedure TglMailSlotServer.Loaded; begin inherited; Open; end;
procedure TglMailSlotServer.Open; begin // создание канала с именем MailSlotName - по этому имени к нему // будут обращаться клиенты h := CreateMailSlot(PChar('\.mailslot' + MailSlotName), 0, MAILSLOT_WAIT_FOREVER,nil); //h:=CreateMailSlot('\.mailslotMailSlot', 0, MAILSLOT_WAIT_FOREVER,nil);
if h = INVALID_HANDLE_VALUE then raise Exception.Create('TglMailSlotServer: Ошибка создания канала !'); Timer.Enabled := true; end;
procedure TglMailSlotServer.Close; begin if h <> 0 then CloseHandle(h); h := 0; end;
procedure TglMailSlotServer.OnTimer(Sender: TObject); var MessageText: string; begin MessageText := ''; // определение наличия сообщения в канале if not GetMailSlotInfo(h,nil,DWORD(MsgNext),@MsgNumber,nil) then raise Exception.Create('TglMailSlotServer: Ошибка сбора информации!');
if MsgNext <> MAILSLOT_NO_MESSAGE then begin beep; // чтение сообщения из канала и добавление в текст протокола if ReadFile(h,str,200,DWORD(read),nil) then MessageText := str else raise Exception.Create('TglMailSlotServer: Ошибка чтения сообщения !'); end;
if (MessageText<>'')and Assigned(OnNewMessage) then OnNewMessage(self, MessageText);
destructor TglMailSlotClient.Destroy; begin inherited; end;
procedure TglMailSlotClient.Loaded; begin inherited; Application.OnException := ErrorCatch; end;
procedure TglMailSlotClient.ErrorCatch(Sender : TObject; Exc : Exception); var UserName: array[0..99] of char; i: integer; begin // получение имени пользователя i:=SizeOf(UserName); GetUserName(UserName,DWORD(i));
Send('/'+UserName+'/'+FormatDateTime ('hh:mm',Time)+'/'+Exc.message); // вывод сообщения об ошибке пользователю Application.ShowException(Exc); end;
function TglMailSlotClient.Send(str: string):boolean; var strMess: string[250]; UserName: array[0..99] of char; h: THandle; i: integer; begin // открытие канала : MyServer - имя сервера // (\.\mailslotxxx - монитор работает на этом же ПК) // xxx - имя канала if FServerName = '' then FServerName := '.'; h:=CreateFile( PChar('\' + FServerName + 'mailslot' + FMailSlotName), GENERIC_WRITE, FILE_SHARE_READ, nil, OPEN_EXISTING, 0, 0); if h <> INVALID_HANDLE_VALUE then begin strMess := str; // передача текста ошибки (запись в канал и закрытие канала) WriteFile(h, strMess, Length(strMess) + 1, DWORD(i), nil); CloseHandle(h); end; Result := h <> INVALID_HANDLE_VALUE; end;
end.
Компонент TglMailSlotServer создает почтовый канал с именем MailSlotName и принимает входящие сообщения. Компонент TglMailSlotClient отправляет сообщения в канал с именем MailSlotName на машине ServerName.
Эти компонеты входят в состав библиотеки GlobusLib, распространяемой с исходными текстами.