Delphi: Пишем шаблон клиент-серверного приложения.
Продолжая тему разработки собственной утилиты администрирования, в данной статье я рассмотрю типовой шаблон программы клиент-сервер, на базе которой можно разрабатывать собственные клиент-серверные приложения. Данный типовой шаблон для простоты понимания и удобства применения будет рассмотрен на примере компонентов ClientSocket и ServerSocket.
Примечание
Для тех, кто не в курсе, что значит клиент-серверное приложение, поясню: это комплекс программ (модулей) состоящий из двух частей — клиентской и серверной. Серверная часть является «главной»- так называемый командный пункт, на который возложена задача поддержания связи со всеми клиентами и раздача команд управления, соответствующих их функционалу (управление клиентами). Клиентская же часть является второстепенной, но не менее важной, так как является важным и связующим элементом, позволяющим выполнять удаленные команды (функции) на компьютере, на котором установлен.
>Компоненты ClientSocket и ServerSocket, которые мы будем использовать, находятся на вкладке Internet. Если на этой вкладке у Вас нет этих компонентов (а по умолчанию при установке Delphi7 они не ставятся), необходимо установить их самостоятельно (пакет dclsocketsXX.bpl). Данный пакет можно найти на установочном диске Delphi7 (или в папке "C:\Temp", куда распаковывается дистрибутив перед установкой — "C:\Temp\delphi7\install\program files\borland\delphi7\bin\") или можете его скачать отсюда. Чтобы установить данный пакет, запустите Delphi7. Зайдите в меню Component->Install Packages. В появившемся окне нажмите кнопку «Add» и укажите место, где расположен пакет dclsocketsXX.bpl. После этого жмите ОК. Компонент на месте.
Надеюсь все объяснил доступно =). А теперь приступим к делу и начнем мы с серверной части. Для этого создадим проект и скинем на форму компонент ServerSocket. В настройках компонента ServerSocket укажем следующее:
Active = false
Name = ss
Port = 4321
ServerType = stNonBlocking
А также для удобства скинем компонент Memo, в который будем выводить всякую инфу. Дадим имя компоненту log.
Далее, для компонента ServerSocket определяем метод onClientConnect, чтобы определять момент подключения клиентов. Вставим следующий код:
procedure TForm1.ssClientConnect(Sender: TObject;
Socket: TCustomWinSocket);
var
myDate : TDateTime;
formattedDateTime : string;
begin
mydate:=Now;
DateTimeToString(formattedDateTime, 'c', myDate);
log.Lines.Add(formattedDateTime+': Есть коннект c '+Socket.RemoteAddress);
{ далее вы можете вставить свой код }
end;
А теперь определим метод onClientRead, в котором будем обрабатывать получаемые сообщения от клиентов:
procedure TForm1.ssClientRead(Sender: TObject; Socket: TCustomWinSocket);
var
s:string;
begin
s:=Socket.ReceiveText;
log.Lines.Add(s);
end;
Определим метод onClientDisconnect, чтобы фиксировать факт отключения клиента:
procedure TForm1.ssClientDisconnect(Sender: TObject;
Socket: TCustomWinSocket);
var
myDate : TDateTime;
formattedDateTime : string;
begin
mydate:=Now;
DateTimeToString(formattedDateTime, 'c', myDate);
log.Lines.Add(formattedDateTime+': Клиент '+socket.RemoteAddress+' отключился.');
end;
На этом с серверной частью покончено.
Приступим к клиентской части. Для этого создадим новый проект, скинем на форму компонент ClientSocket и таймер. В настройках компонента укажем следующее:
Active = false
Name = сs
Port = 4321
ClientType = ctNonBlocking
Address = 127.0.0.1
Для простоты пояснения я в Address указал «петлю». Но для гибкости приложения рекомендую это поле обрабатывать программно, во время CreateForm при обработке конфигурационного файла, в котором можно указывать нужный IP-адрес сервера.
Здесь также для удобства скинем на форму компонент Memo, в который будем выводить техническую инфу. Имя дадим соответствующее log.
Для компонента ClientSocket определяем метод onError для того, чтобы обрабатывать исключения, возникшие в момент подключения клиента к серверу. Вставим следующий код:
procedure TForm1.csError(Sender: TObject; Socket: TCustomWinSocket;
ErrorEvent: TErrorEvent; var ErrorCode: Integer);
var
myDate : TDateTime;
formattedDateTime : string;
begin
if ErrorEvent= eeConnect then
begin
cs.Active:=false;
{добавить запись в журнал};
mydate:=Now;
DateTimeToString(formattedDateTime, 'c', myDate);
log.lines.Add(formattedDateTime+': Невозможно установить соединение с сервером - '+cs.Address);
end;
ErrorCode:=0;
{ далее вы можете вставить свой код }
end;
Теперь определим метод onConnect. Вставим следующий код:
procedure TForm1.csConnect(Sender: TObject; Socket: TCustomWinSocket);
var
myDate : TDateTime;
formattedDateTime : string;
begin
mydate:=Now;
DateTimeToString(formattedDateTime, 'c', myDate);
log.lines.Add(formattedDateTime+': Соединение с сервером - '+socket.RemoteAddress+' установлено.');
end;
И чтобы фиксировать момент потери связи с сервером, определим метод onDisconnect:
procedure TForm1.csDisconnect(Sender: TObject; Socket: TCustomWinSocket);
var
myDate : TDateTime;
formattedDateTime : string;
begin
mydate:=Now; //получим текущее время
DateTimeToString(formattedDateTime, 'c', myDate); //преобразуем в строку
log.Lines.Add(formattedDateTime+': Соединение с сервером '+socket.RemoteAddress+' потеряно.');
end;
Таймер настроим так:
Enabled = true
Name = te
Interval = 5000
И определяем метод onTimer. Вставим следующий код:
procedure TForm1.Timer1Timer(Sender: TObject);
begin
if not cs.Active then
begin
cs.Active:=true;
end;
cs.Socket.SendText('ping client');
end;
Данный код проверяет наличие соединения с сервером и в случае его отсутствия пытается его установить.
И каждые 5 секунд отправляет серверу сообщение «ping client».
Вот примерно так выглядит типовой шаблон приложения «клиент-сервер».
Примечание
Хотел бы обратить внимание на обработчик onError тех, кто ранее не знал как избавиться от злосчастного сообщения — «Asynchronous socket error 10061», возникающее при попытке осуществления подключения к серверу, который недоступен.
Если есть кому что добавить или задать вопрос по теме — прошу отписываться в комментах.
Update: Тут были некоторые ссылки на скачивание, но они стали битыми. По просьбе можно попробовать восстановить.
Update 2: К сожалению, такой возможности на данный момент уже нет.
Можно получить ссылочку на собранный проект? Что-то у меня с косяками выходит.
@Николай
Признаться, шансы не велики. Я передам автору статьи, если будет такая возможность - он с вами свяжется. Сам, к сожалению, помочь не могу - не дельфист.
@Николай
Увы, судя по всему, у автора нет времени. Но вы можете описать свою проблему здесь, может, кто-нибудь поможет. :)
Наверно уже поздно, но всё-таки...
В статье только один косяк. Здесь по инструкции у сервера выставляется Active = False.
Таким образом сервер не запускается автоматически при старте программы. Можно или выставить Active = True в свойствах, или прописать в нужном месте, например на нажатие кнопки ss.Active:=True;
А так, полезная статья, спасибо автору! :)
Подскажите плиз:
В локальной сети все ок, но как соединиться с сервером если у него есть IP адрес (например 45.112.14.391 ) и сетевой адрес ( 192.168.1.5) ?
192.168.1.5 - это локальный ip
чтобы сконектиться с внешним ip 45.112.14.391 - просто укажи его в подключении, но на компе -сервере, ты должен открыть в роутере или брандмауэре порт, по которому будет работать прога (4321) и все получиться
Востановите пожалуйста ссылки. Я сделал всё как написано. в меме клиента пишет "21.12.2013 17:07:41: Невозможно установить соединение с сервером - 192.168.1.3
"
@Аноним
Сожалею, но такой возможности нет (раньше была).
Тут несколько советов (сразу говорю, я в дельфи - "ни в зуб ногой"), попробуй:
1. Указать в параметрах сервера адрес не 127.0.01, а 0.0.0.0 или 192.168.1.3 (похожий совет есть в комментах выше).
2. Воспользоваться советом выше и выставить Active = True (без понятия что это :) ).
3. Подключиться к серверу с помощью telnet. Если и telnet не подключается, то хотя бы будет понятно что проблема не в клиенте. Попробуй на этой же машине запустить какой-нибудь заведомо рабочий сервер и подключись на его порт, если тоже не будет работать - проблема в фаерволле.
4. Попробуй подключиться клиентом на любой веб-сервер (80й порт).
Вы забыли указать,что сервак нужно включить.
У меня вопрос,как-нибудь возможно проверить работу на одном компьютере? Клиент работает вроде,пишет "Установить соединение с клиентом 127.0.0.1",это верно или же нет
Метод OnConnect неправильно обрабатывается. У меня пишет что коннект установлен, хотя это невозможно. Хотя на совсем уже неверные адреса не пишет.
Доброго времени суток всем, скажите пожалуйста, а как устанавливать связь с сервером если все компы в сетке сидят на динамических айпишниках и обратиться к серверу можно только по имени компа