Чтение онлайн

на главную - закладки

Жанры

Шрифт:

Одним из самых сложных моментов работы рассматриваемого сервера является обеспечение синхронизации доступа к массиву clients. Для этого используется критическая секция. Она также применяется для синхронизации добавления событий в список IstEvents сервера.

И, наконец, последний момент в реализации сервера. Чтобы сервер можно было запускать с отключенным протоколированием событий, а также чтобы окно сервера не мешало пользователю, можно хранить значения переменных REPORT и SERVERVISIBLE в INI-файле. Так, собственно, и сделано: значения этих переменных хранятся в секции [Common] файла Server. ini. Для считывания значений из INI-файла при запуске сервера код в модуле Server (файл Server. dpr) изменен следующим образом (листинг 11.21).

...

Листинг 11.21. Изменения в модуле Server

program Server;

uses

Forms,

Unit1 in \'Unit1.pas\' {frmServer},

IniFiles, Dialogs;

{$R *.res}

var

{Переменные из INI-файла}

config: TIniFile;

strPath: string;

begin

//Грузим информацию из INI-файла

strPath :=

Copy(Application.ExeName,1,Length(Application.ExeName)–3) +

\'ini\

config := TIniFile.Create(strPath);

SERVERVISIBLE := config.ReadBool(\'Common\', \'ServerVisible\',

False);

REPORT := config.ReadBool(\'Common\',’EventReport’, False);

config.Free ;

try

//Запуск сервера

Application.Initialize;

Application.CreateForm(TfrmServer, frmServer);

Application.Run;

except

MessageDlg(\'Не удается запустить сервер сообщений. \' +

\'Возможно, он был запущен ранее.\', mtError, [mbOK], 0);

end;

end.

В приведенном листинге код создания формы помещен в блок try. Сделано это только для того, чтобы сервер не «падал» с выдачей всем прекрасно знакомого окна о критической ошибке при попытке ошибочного запуска своей копии.

Соответственно, INI-файл для запуска сервера с видимым окном и включенным протоколированием имеет следующий вид:

...

[Common]

ServerVisible=1

EventReport=1

Реализация клиентского приложения

Проект клиентской программы имеет имя Client. Внешний вид формы клиентского приложения во время его работы представлен на рис. 11.7.

Приведенная на рис. 11.7 форма имеет имя frmClient. Свойства (только существенные для работы приложения) основных элементов управления, помещенных на форму, приведены в табл. 11.2.

Рис. 11.7. Форма клиента при ведении разговора

Таблица 11.2.

Свойства элементов управления формы frmClient

Далее приведены функции и процедуры, не являющиеся обработчиками событий, но имеющие большое значение для работы клиентского приложения.

Приведенная в листинге 11.22 процедура обновляет форму при удачном подключении к серверу.

...

Листинг 11.22.

Обновление формы при присоединении к серверу

procedure Connect;

begin

with frmClient do

begin

cmbConnect.Caption := \'Отключиться\

txtUser.Enabled := False;

txtServer.Enabled := False;

Caption := \'Разговорник [\' + txtUser.Text + \' подключен к \' +

txtServer.Text + \']\

lstUsers.Enabled := True;

cmbSend.Enabled := True;

txtMessage.Enabled := True;

txtChat.Enabled := True;

end;

end;

Процедура Disconnect, приведенная в листинге 11.23, обновляет форму при отключении от сервера (в таком виде форма frmClient предстает первоначально).

...

Листинг 11.23.

Обновление формы при отсоединении от сервера

procedure Disconnect;

begin

with frmClient do

begin

cmbConnect.Caption := \'Подключиться\

txtUser.Enabled := True;

txtServer.Enabled := True;

Caption := \'Разговорник\

lstUsers.Enabled := False;

lstUsers.Clear;

cmbSend.Enabled := False;

txtMessage.Enabled := False;

txtChat.Enabled := False;

end;

end;

Процедура ProcessMessage (листинг 11.24) обрабатывает сообщение, полученное от сервера, аналогично такой же процедуре в серверном приложении (естественно, сообщения и реакция на них отличны от серверных).

...

Листинг 11.24.

Обработка строки, полученной от сервера

procedure ProcessMessage(strMessage: string);

var

strAction: string; //Тип сообщения (префикс сообщения)

len: Integer; //Длина строки strAction

begin

//Определим тип сообщения и выполним соответствующие действия

len := Pos(\':\', strMessage);

strAction := Copy(strMessage,1,len-1);

Delete(strMessage,1,len);

if (strAction = \'ok\') then

begin

//Регистрация пользователя завершена – можно отправлять

//сообщения

Connect;

end

else if (strAction = \'error\') then

begin

//Ошибка!!!

frmClient.TCPClient.Disconnect;

Disconnect;

MessageDlg(strMessage, mtError, [mbOK], 0);

end

else if (strAction = \'adduser\') then

begin

//К разговору присоединился новый пользователь

frmClient.lstUsers.Items.Add(strMessage);

end

else if (strAction = \'deluser\') then

begin

//Какой-то пользователь отсоединился

frmClient.lstUsers.Items.Delete(

frmClient.lstUsers.Items.IndexOf(strMessage));

end

else begin

//Покажем принятое сообщение

frmClient.txtChat.Lines.Add(strMessage);

end;

end;

Далее приводятся обработки событий, на которых, собственно, и основана работа клиентской программы. Обработчик нажатия кнопки cmbConnect, приведенный в листинге 11.25, пытается присоединиться к серверу. Если клиент присоединен к серверу, то эта же кнопка используется для его отсоединения.

...

Листинг 11.25.

Присоединение/отсоединение от сервера

procedure TfrmClient.cmbConnectClick(Sender: TObject);

begin

if (cmbConnect.Caption = \'Подключиться\') then

begin

//Проверим, чтобы были введены имя сервера

//и имя пользователя

if (txtServer.Text = \'\')then

begin

MessageDlg(\'Введите имя сервера в текстовое поле.\',

mtInformation, [mbOK], 0);

Exit;

end

else if (txtUser.Text = \'\')then

begin

MessageDlg(\'Введите имя пользователя в текстовое поле.\',

mtInformation, [mbOK], 0);

Exit;

end;

//Пытаемся подключиться к серверу

try

TCPClient.Host := txtServer.Text;

TCPClient.Connect;

except

MessageDlg(\'Не удается соединиться с сервером\',mtError,

[mbOK], 0);

end;

end

else

//Отключаемся от сервера

TCPClient.Disconnect;

end;

Обработчик нажатия кнопки cmbSend (листинг 11.26) отправляет сообщение, которое могут прочесть все пользователи, присоединенные к серверу.

...

Листинг 11.26.

Отправка сообщения всем собеседникам

procedure TfrmClient.cmbSendClick(Sender: TObject);

begin

if (txtMessage.Text <> \'\') then

begin

//Отправка сообщения всем собеседникам

TCPClient.WriteLn(\'text:\' + txtMessage.Text);

txtMessage.Text := \'\

txtMessage.SetFocus;

end;

end;

При двойном щелчке кнопкой мыши на имени в списке пользователей отправляется сообщение, которое получает только выделенный в списке пользователь (листинг 11.27).

...

Листинг 11.27.

Отправка сообщения заданному собеседнику

procedure TfrmClient.lstUsersDblClick(Sender: TObject);

begin

if ((lstUsers.ItemIndex >= 0) and (txtMessage.Text <> \'\'))

then

begin

//Отправим сообщение только для выбранного собеседника

//(сообщение вида «имя_собеседника:текст_сообщения»)

TCPClient.WriteLn(lstUsers.Items.Strings[lstUsers.ItemIndex] +

\':\' + txtMessage.Text);

txtMessage.SetFocus;

end;

end;

Поделиться:
Популярные книги

Волкодав

Семёнова Мария Васильевна
1. Волкодав
Фантастика:
фэнтези
героическая фантастика
9.46
рейтинг книги
Волкодав

Возвращение

Кораблев Родион
5. Другая сторона
Фантастика:
боевая фантастика
6.23
рейтинг книги
Возвращение

Мастер порталов

Лисина Александра
8. Гибрид
Фантастика:
боевая фантастика
попаданцы
технофэнтези
аниме
фэнтези
5.00
рейтинг книги
Мастер порталов

Кодекс Охотника. Книга ХХХ

Винокуров Юрий
30. Кодекс Охотника
Фантастика:
попаданцы
аниме
фэнтези
5.00
рейтинг книги
Кодекс Охотника. Книга ХХХ

Цеховик. Книга 2. Движение к цели

Ромов Дмитрий
2. Цеховик
Фантастика:
попаданцы
альтернативная история
5.00
рейтинг книги
Цеховик. Книга 2. Движение к цели

Гримуар темного лорда V

Грехов Тимофей
5. Гримуар темного лорда
Фантастика:
попаданцы
аниме
фэнтези
5.00
рейтинг книги
Гримуар темного лорда V

Моров. Том 5

Кощеев Владимир
4. Моров
Фантастика:
фэнтези
попаданцы
аниме
5.00
рейтинг книги
Моров. Том 5

Великие мифы и легенды. 100 историй о подвигах, мире богов, тайнах рождения и смерти

Мудрова Ирина Анатольевна
Старинная литература:
мифы. легенды. эпос
5.00
рейтинг книги
Великие мифы и легенды. 100 историй о подвигах, мире богов, тайнах рождения и смерти

Набирая силу

Рокотов Алексей
2. Путь князя
Фантастика:
фэнтези
5.00
рейтинг книги
Набирая силу

Потомок бога 3

Решетов Евгений Валерьевич
3. Локки
Фантастика:
аниме
фэнтези
5.00
рейтинг книги
Потомок бога 3

Кодекс Императора II

Сапфир Олег
2. Кодекс Императора
Фантастика:
аниме
фэнтези
попаданцы
5.00
рейтинг книги
Кодекс Императора II

Я снова царь. Книга XXXIII

Дрейк Сириус
33. Дорогой барон!
Фантастика:
юмористическое фэнтези
аниме
попаданцы
5.00
рейтинг книги
Я снова царь. Книга XXXIII

Бояръ-Аниме. Газлайтер. Том 34

Володин Григорий Григорьевич
34. История Телепата
Фантастика:
фэнтези
боевая фантастика
аниме
5.00
рейтинг книги
Бояръ-Аниме. Газлайтер. Том 34

Петля, Кадетский Корпус. Книга четвертая

Алексеев Евгений Артемович
4. Петля
Фантастика:
боевая фантастика
попаданцы
аниме
5.00
рейтинг книги
Петля, Кадетский Корпус. Книга четвертая