Шрифт:
Интервал:
Закладка:
IntToStr(imgScreen.Height));
//....получаем данные
stream := TMemoryStream.Create;
ReadStream(stream);
stream.Position := 0;
//....формируем изображение
imgScreen.Picture.Bitmap.LoadFromStream(stream);
stream.Clear;
stream.Free;
end;
end;
В тексте листинга 11.8 создано большое количество комментариев, поэтому дополнительно пояснять его нет смысла. Остановимся лишь на том, зачем в процедуре TForml.TimerlTimer предусмотрено два варианта получения изображения с сервера.
Все дело в том, что сжатие (в нашем примере разрешение экрана наблюдаемого компьютера больше размера компонента imgScreen) на стороне сервера требует от компьютера, на котором запущено серверное приложение, большего процессорного времени на снятие копии экрана. Это снижает нагрузку на сеть при передаче изображения, а также экономит ресурсы компьютера-клиента. Но качество сжатого изображения в этом случае получается несколько хуже, чем когда мы предоставляем компоненту Image возможность масштабировать изображение самостоятельно.
Если же не использовать сжатие изображения на сервере, возрастает нагрузка на сеть при передаче полноразмерной копии экрана, а вся работа по сжатию изображения возлагается на компонент imgScreen (то есть дополнительно тратится процессорное время на компьютере клиента). При большом разрешении экрана наблюдаемого компьютера (или при наблюдении сразу за несколькими компьютерами) машина клиента, если она недостаточно мощная, может начать весьма ощутимо «тормозить». Качество сжатого изображения при этом получается более высоким.
В качестве более-менее эффективного решения можно предложить использовать большие промежутки времени между запросами данных с сервера слежения с масштабированием изображения на серверной стороне (если только машина сервера не является очень маломощной).
11.4. Многопользовательский разговорник
В завершение знакомства с компонентамиIdTCPCLient и IdTCPServer для организации сетевого взаимодействия рассмотрим создание полноценного клиент-серверного приложения – многопользовательского разговорника. Как можно догадаться из названия, это приложение будет позволять обмениваться сообщениями большому количеству пользователей (наподобие чата).
Поскольку этот пример будет несколько сложнее (в плане организации сетевого взаимодействия) предыдущих примеров главы, то рассмотрим подробно основные этапы его проектирования, разработки и реализации (начиная с требований и поведения клиента и сервера и заканчивая нюансами реализации приложений).
Требования к клиентскому и серверному приложениям
Пользователи при работе с клиентскими приложениями должны иметь следующие возможности:
• видеть полный текст разговора с момента их подключения к серверу;
• отсылать сообщения как всем, так и только определенным пользователям;
• видеть список пользователей, участвующих в разговоре (при этом список должен автоматически обновляться при отключении или присоединении новых пользователей);
• получать уведомления об отключении или присоединении новых пользователей (прямо в тексте разговора).
Серверное приложение, кроме управления подключением, отключением пользователей, а также доставки сообщений, должно обеспечивать протоколирование событий (подключение, отключение пользователей, от кого и кому послано то или иное сообщение).
При реализации серверного приложения нужно преодолеть некоторые сложности, связанные с тем, что к серверу будут постоянно подключены сразу несколько пользователей, причем информация о каждом пользователе будет постоянно храниться и использоваться сервером. Нужно также обеспечить надежную работу клиентского, а главное – серверного приложения при проблемах, связанных с неисправностями сети.
И, наконец, нужно обеспечить автоматическую рассылку клиентским приложениям следующей информации (клиенты эту информацию специально с сервера не запрашивают):
• текста сообщений;
• уведомлений о присоединении или отсоединении пользователей.
Формат сообщений клиента и сервера
Клиент и сервер обмениваются только текстовыми сообщениями (не путать с сообщениями, которыми обмениваются пользователи в ходе разговора). Строка любого сообщения состоит из двух частей: префикса и текста сообщения. Префикс отделяется от текста сообщения символом: (двоеточие). По префиксу можно определить, что делать с полученным сообщением.
Возможны следующие сообщения от клиента серверу:
• name: имя_пользователя – при помощи этого сообщения клиентская программа сообщает серверу, под каким именем зарегистрировать пользователя (это имя будут видеть другие пользователи);
• text: текст – при получении этого сообщения сервер должен разослать текст всем участникам разговора (включая отправителя);
• имя_адресата: текст – при получении этого сообщения сервер должен отправить текст только заданному префиксом пользователю имяадресата, а также должен отправить копию автору сообщения.
К сообщениям третьего типа относятся все сообщения, принимаемые сервером и не начинающиеся с text: или name:.
В свою очередь, сервер может посылать клиентской программе сообщения следующего вида:
• ok: – означает, что пользователь зарегистрирован и может вступать в разговор;
• error: сообщение_об_ошибке – означает, что по каким-то причинам пользователь не может участвовать в разговоре. При получении этого сообщения клиентская программа должна показать окно с текстом сообщение_об_ошибке и разорвать соединение с сервером;
• adduser: имя_пользователя – при получении такого сообщения клиентская программа должна добавить строку имя_пользователя в список участников разговора;
• deluser: имя_пользователя – при получении такого сообщения клиентская программа должна удалить строку имя_пользователя из списка участников разговора;
• text: текст – клиентская программа должна добавить текст к тексту разговора.
Перед рассмотрением реализации клиентской и серверной частей скажем несколько слов об использовании специальных сообщений клиента (name: имя пользователя) и сервера (ok: и error: сообщение_об_ошибке). Дело в том, что в предлагаемой реализации сервера присоединение нового пользователя к разговору происходит следующим образом.
1. Клиентское приложение присоединяется к серверу (количество пользователей ограничено, поэтому сервер может послать лишнему пользователю сообщение error: с соответствующим текстом, описывающим ошибку, и тут же разорвать установленное соединение).
2. Клиентское приложение посылает серверу сообщение с именем пользователя (префикс name:).
3. Если имя, под которым хочет зарегистрироваться новый пользователь, используется, то клиентскому приложению отправляется сообщение error: с пояснением ошибки.
4. Если имя свободно, то сервер сохраняет его (и рассылает его всем остальным клиентским приложениям), а также посылает приложению присоединенного пользователя список всех остальных пользователей, и только после этого дает новому пользователю возможность участвовать в разговоре (сообщение ok:).
Остальные нюансы будут рассмотрены при описании исходного кода клиентского и серверного приложений.
Реализация сервера
Серверное приложение реализовано с оконным интерфейсом. Форма f rmServer приложения во время работы представлена на рис. 11.6.
Рис. 11.6. Форма сервера сообщений
Элемент управления ListBox (имя IstEvents), который можно увидеть на форме, предназначен для вывода списка событий (присоединение, отсоединение клиентов, передача сообщений). Список помещается в рамку GroupBoxl. Для списка и рамки задано значение свойства align = client.
Кроме перечисленных элементов управления, на форму также помещены компоненты IdTCPServer (имя TCPServer)n Timer (имя Timerl). Для таймера задаются значения свойств Enabled = True и Intervel = 50. Компонент TCPServer настраиваем на прослушивание порта 12345, а также устанавливаем значение свойства Active = True.
При реализации сервера основной программный код помещен в файле формы (Unitl. pas). Этот модуль условно можно разделить на две части: в первой реализованы специальные функции и процедуры (регистрации пользователей, пересылки текстовых сообщений между пользователями и т. д.), во второй части следуют процедуры-обработчики событий (методы класса TfrmServer).
Сначала рассмотрим процедуры обработки событий, так как они значительно проще, чем остальные функции и процедуры, и их рассмотрение вначале позволит лучше представить функционирование приложения (листинг 11.9)....Листинг 11.9.
Процедуры обработки событий серверного приложения (Unitl.pas)
procedure TfrmServer.Timer1Timer(Sender: TObject);
begin
//Если нужно, то скроем окно сервера
if (not SERVERVISIBLE) then
begin
frmServer.Visible := False;
ShowWindow(Application.Handle,SW_HIDE);
end;
//Таймер больше не нужен
Timer1.Enabled := False;
end;
procedure TfrmServer.TCPServerExecute(AThread: TIdPeerThread);
begin
//Обработаем сообщение, пришедшее от клиента
- Excel. Легкий старт - Дмитрий Донцов - Программы
- Фотоприколы с помощью Photoshop - Юрий Гурский - Программы
- 3ds Max 2008 - Владимир Верстак - Программы
- ArchiCAD. Начали! - Андрей Орлов - Программы
- Word 2007. Легкий старт - Дмитрий Донцов - Программы
- Домашняя бухгалтерия и личные финансы на компьютере - Алексей Гладкий - Программы
- 1С:Предприятие. Зарплата и кадры. Секреты работы - Дмитрий Рязанцев - Программы
- Microsoft Access 2007 - Александр Днепров - Программы
- Самые полезные программы: утилиты - Виталий Леонтьев - Программы
- Работа в Интернете - Дмитрий Макарский - Программы