Разработка отказоустойчивой вычислительной системы
Содержание
Введение
Постановка задачи
Алгоритм работы
Функции и процедуры
Интерфейс
Код программы
Заключение
Введение
Отказоустойчивой вычислительной системой
называют среду, которая предоставляет постоянное, непрерывное обслуживание -
доступ к данным и приложениям - даже в случае возникновения сбоев в аппаратных,
программных или сетевых компонентах.
Старый лозунг службы Federal Express звучит так:
«В любом случае почта должна быть доставлена за ночь». Примерно таковы и
требования к современным компьютерным системам, за исключением того, что
доставка информации должна гарантироваться не за одну ночь, а постоянно, вне
зависимости от проблем, которые могут возникнуть в конкретных аппаратных или
программных компонентах информационной системы, сбоев в сети электропитания или
неприятностей другого рода.
Такая концепция называется отказоустойчивостью.
Системы обеспечения отказоустойчивости встраиваются в программное обеспечение,
входят в состав аппаратных средств либо являются комбинированными.
В рамках курса отказоустойчивые вычислительные
системы, была поставлена задача разработать простой пример работы
отказоустойчивой системы на основе клиент-серверной технологии.
Постановка задачи
Создать программный продукт на основании
клиент-серверной технологии, реализующий отказоустойчивую работу системы. В
случае потери связи с одним из серверов клиент подключается на другой сервер.
В случае потере связи с обоими серверами клиент
продолжит искать работоспособный сервер из списка доступных серверов, пока не
подключится к одному из них, либо пока работа приложения не будет остановлена.
Для примера будет реализован сервер погоды, и клиент запрашивающий погоду с
сервера.
Алгоритм работы
программный отказоустойчивый сервер
клиент
1. Запускается сервер и альтернативный
сервер, прослушивающие 999 порт по всем диапазонам айпи адресов. В случае
получения пакета по этому порту анализируется содержащаяся в пакете информация,
если первый символ “p” то это
пакет проверки связи от клиента, после символа «p»
содержится айпи адрес отправителя на который отправляется пакет аналогичного
типа с информацией о том что сервер доступен. Если второй символ «z»,
то это запрос погоды, в таком случае сервер формирует ответный пакет содержащий
информацию о температуре воздуха и облачности.
. Клиент после запуска начинает с
определенной частотой отправлять пакеты проверки связи на первый адрес из
списка серверов. В случае возвращения ответного пакета, клиент понимает о том
что связь с сервером в порядке. В случае если в установленный интервал ответный
пакет не вернулся, осуществляется две повторных попытки подключения на этот же
сервер, далее в случае успеха «рабочим» сервером остается все тот же, иначе
осуществляется проверка связи со вторым сервером в списке, потом с третьим и
т.д. Когда список серверов заканчивается клиент повторяет попытку подключения к
первому.
. При запросе погоды клиент отправляет
запрос на текущий сервер. Полученный пакет он разбирает, и формирует для
представления пользователю.
Структура пакетов:
«Пинг» клиента:
Р<адрес клиента>
«Пинг» сервера:
Р
Запрос погоды:
Z<адрес клиента>
Ответ с погодой
Z;температура;
облачность; - ; разграничение для анализа строки
Функции и процедуры
Клиент
Функция получения своего айпи:TForm1.GetLocalIP:
String;
Процедура запроса погоды, клиентом:
procedure
TForm1.Button1Click(Sender: TObject);
Процедура получения
пакета
клиентом:
procedure TForm1.sUDPRead(Sender:
TObject; AData: TStream;
ABinding: TIdSocketHandle);
Процедура, таймер проверки связи с сервером:
Процедура, таймер проверки был ли получен ответ
от сервера в установленное время
procedure TForm1.Timer2Timer(Sender:
TObject);
Процедура установка начальный параметров
клиента:
procedure TForm1.FormCreate(Sender:
TObject);
Процедура управления
формой:TForm1.Button3Click(Sender:
TObject);
Сервер
Функция получения своего айпи:TForm1.GetLocalIP:
String;
Процедура установка начальный параметров
клиента:
procedure TForm1.FormCreate(Sender:
TObject);
Процедура анализа полученного пакета и
соответствующего ответа:
procedure TForm1.sUDPRead(Sender:
TObject; AData: TStream;
ABinding: TIdSocketHandle);
Интерфейс
Форма сервера:
Форма клиента:
Код программы
unit Unit1; interface uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs,IdSocketHandle, StdCtrls, IdBaseComponent, IdComponent,
IdTCPConnection, IdTCPClient, IdUDPBase, IdUDPClient, ExtCtrls, IdUDPServer,
IdTCPServer, jpeg, Buttons, FileCtrl,WinSock; type TForm1 = class(TForm)
Button1: TButton; s: TIdUDPServer; c: TIdUDPClient; Eip: TEdit; Timer1:
TTimer; Timer2: TTimer; Memo1: TMemo; Image1: TImage; Label1: TLabel; Label2:
TLabel; Label3: TLabel; Label4: TLabel; Eip2: TEdit; Label5: TLabel; Eport:
TEdit; Button2: TButton; Button3: TButton; Bevel1: TBevel; procedure
Button1Click(Sender: TObject); procedure sUDPRead(Sender: TObject; AData:
TStream; ABinding: TIdSocketHandle); procedure Timer1Timer(Sender: TObject);
procedure Timer2Timer(Sender: TObject); procedure Button2Click(Sender:
TObject); procedure s2UDPRead(Sender: TObject; AData: TStream; ABinding:
TIdSocketHandle); procedure FormCreate(Sender: TObject); procedure
Button3Click(Sender: TObject); var i : integer; mas : array [0..1000] of
char; str,pg : string; begin if numP<>0 then begin if ncs=1 then Memo1.Lines.Add('Ïîäêëþ÷åíèå
ê ñåðâåðó 1
âîñòàíîâëåííî')
else Memo1.Lines.Add('Ïîäêëþ÷åíèå
ê ñåðâåðó 2
âîñòàíîâëåííî');
end; numP:=0; timer2.Enabled:=false; Adata.Read(mas,100); for i:=0 to 1000 do
begin if mas[i]<>'' then str:=str+mas[i] else break; end; if mas[0]='z'
then begin if mas[1]='d' then Image1.Picture.LoadFromFile('d.jpg'); if
mas[1]='p' then Image1.Picture.LoadFromFile('p.jpg'); if mas[1]='s' then
Image1.Picture.LoadFromFile('s.jpg'); if mas[1]='o' then
Image1.Picture.LoadFromFile('o.jpg'); for i:=2 to 1000 do begin if mas[i]<>'#'
then pg:=pg+mas[i] else break; end; label1.Caption:=pg; end; end; procedure
TForm1.Timer1Timer(Sender: TObject); begin //c.Host:=eip.Text;
c.Port:=strtoint(eport.text) ; c.Active:=true; c.Send('p'+Mip+'!');
c.Active:=false; timer2.Enabled:=true;
|
private function GetLocalIP:
String; { Private declarations } public { Public declarations } Mip:string;
ncs:byte; end; var Form1: TForm1; numP: byte; implementation {$R *.dfm}
function TForm1.GetLocalIP: String; const WSVer = $101; var wsaData:
TWSAData; P: PHostEnt; Buf: array [0..127] of Char; begin Result := ''; if
WSAStartup(WSVer, wsaData) = 0 then begin if GetHostName(@Buf, 128) = 0 then
begin P := GetHostByName(@Buf); if P <> nil then Result :=
iNet_ntoa(PInAddr(p^.h_addr_list^)^); end; WSACleanup; end; end; procedure
TForm1.Button1Click(Sender: TObject); begin c.Port:=strtoint(eport.text);
c.Active:=true; c.Send('z'+ GetLocalIP); c.Active:=false; end; procedure
TForm1.sUDPRead(Sender: TObject; AData: TStream; ABinding: TIdSocketHandle);
end; procedure TForm1.Timer2Timer(Sender: TObject); begin if numP=0 then
begin if ncs=1 then Memo1.Lines.Add('Ïîòåðÿííà
ñâÿçü ñ
ñåðâåðîì 1.
Ïîïûòêà ïîäêëþ÷åíèÿ
¹1') else
Memo1.Lines.Add('Ïîòåðÿííà
ñâÿçü ñ
ñåðâåðîì 2.
Ïîïûòêà ïîäêëþ÷åíèÿ
¹1'); end;
if numP=1 then begin if ncs=1 then Memo1.Lines.Add('Ïîòåðÿííà
ñâÿçü ñ
ñåðâåðîì 1.
Ïîïûòêà ïîäêëþ÷åíèÿ
¹2') else
Memo1.Lines.Add('Ïîòåðÿííà
ñâÿçü ñ
ñåðâåðîì 2.
Ïîïûòêà ïîäêëþ÷åíèÿ
¹1'); end;
if numP>1 then begin timer2.Enabled:=false; if ncs=1 then begin
c.Host:=eip2.Text; ncs:=2; numP:=0; Memo1.Lines.Add('Ïîòåðÿííà
ñâÿçü ñ
ñåðâåðîì 1.
Ïîïûòêà ïîäêëþ÷åíèÿ
êî âòîðîìó'); end
else begin c.Host:=eip.Text ; ncs:=1; numP:=0; Memo1.Lines.Add('Ïîòåðÿííà
ñâÿçü ñ
ñåðâåðîì 2.
Ïîïûòêà ïîäêëþ÷åíèÿ
ê ïåðâîìó'); end;
end; numP:=numP+1; end; procedure TForm1.Button2Click(Sender: TObject); begin
s.DefaultPort:=strtoint(eport.Text) end; procedure TForm1.s2UDPRead(Sender:
TObject; AData: TStream;
|
ABinding: TIdSocketHandle); var i
: integer; mas : array [0..1000] of char; str : string; begin Adata.Read(mas,100);
for i:=0 to 1000 do begin if mas[i]<>'' then str:=str+mas[i] else
break; end; timer2.Enabled:=false; end; procedure TForm1.FormCreate(Sender:
TObject); begin Mip:=GetLocalIP; c.Host:=eip.Text; numP:=0; ncs:=1; end;
procedure TForm1.Button3Click(Sender: TObject); begin if Button3.caption='Ñêðûòü
íàñòðîéêè' then
|
begin label2.Visible:=false;
label3.Visible:=false; label4.Visible:=false; label5.Visible:=false;
eip.Visible:=false; eip2.Visible:=false; eport.Visible:=false;
Button2.Visible:=false; Memo1.Visible:=false; Form1.Height:=180; button3.Caption:='Ïîêàçàòü
íàñòðîéêè'; end
else begin label2.Visible:=true; label3.Visible:=true; label4.Visible:=true;
label5.Visible:=true; eip.Visible:=true; eip2.Visible:=true;
eport.Visible:=true; Button2.Visible:=true; Memo1.Visible:=true;
Form1.Height:=400; Button3.caption:='Ñêðûòü
íàñòðîéêè'; end
end; end.
|
Код программы сервера:
unit Unit1; interface uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs,IdSocketHandle, StdCtrls, IdBaseComponent, IdComponent,
IdTCPConnection, IdTCPClient, IdUDPBase, IdUDPClient, ExtCtrls, IdUDPServer,
IdTCPServer, jpeg, Buttons, FileCtrl,WinSock; type TForm1 = class(TForm) s:
TIdUDPServer; c: TIdUDPClient; Eport: TEdit; Button2: TButton; Edit1:
TEdit; end; var Form1: TForm1; implementation {$R *.dfm} function
TForm1.GetLocalIP: String; const WSVer = $101; var wsaData: TWSAData; P:
PHostEnt; Buf: array [0..127] of Char; begin Result := ''; if
WSAStartup(WSVer, wsaData) = 0 then begin if GetHostName(@Buf, 128) = 0 then
begin P := GetHostByName(@Buf); if P <> nil then Result :=
iNet_ntoa(PInAddr(p^.h_addr_list^)^); end; WSACleanup; end; end; procedure
TForm1.sUDPRead(Sender: TObject; AData: TStream; ABinding: TIdSocketHandle);
var i : integer; zap: boolean; mas : array [0..1000] of char; str,pg :
string; begin zap:=false; str:=''; Adata.Read(mas,100); for i:=1 to 1000 do
begin if mas[i]<>'!' then str:=str+mas[i] else
|
Label1: TLabel; Label2: TLabel;
Edit2: TEdit; RadioButton1: TRadioButton; RadioButton2: TRadioButton;
RadioButton3: TRadioButton; RadioButton4: TRadioButton; Label3: TLabel;
Label4: TLabel; function GetLocalIP: String; procedure sUDPRead(Sender:
TObject; AData: TStream; ABinding: TIdSocketHandle); procedure
Button2Click(Sender: TObject); procedure FormCreate(Sender: TObject); private
{ Private declarations } public { Public declarations } break; end; if
mas[0]='p' then begin c.Host:=str; c.Port:=strtoint(eport.text);
c.Active:=true; c.Send('p1o'); c.Active:=false; end; if mas[0]='z' then begin
c.Host:=str; c.Port:=strtoint(eport.text); c.Active:=true; if
RadioButton1.Checked then pg:='s'; if RadioButton2.Checked then pg:='p'; if
RadioButton3.Checked then pg:='o'; if RadioButton4.Checked then pg:='d';
c.Send('z'+pg+edit2.Text+'#'); c.Active:=false; end; end; procedure
TForm1.Button2Click(Sender: TObject); begin s.Active:=true; end; procedure
TForm1.FormCreate(Sender: TObject); begin label4.Caption:=Form1.GetLocalIP
end; end.
|
Заключение
Получен программный продукт, реализующий
отказоустойчивую систему на основе клиент серверной технологии. Программа
проверена на практике. В случае потери связи с ведущим сервером клиент успешно
переключается на альтернативный. Поставленная задача выполнена.