Інформація про нас Розроблені нами програми Наші інтернет-розробки Фотогалерея наших робіт Документація до програм, наші статті, а також перезентації наших програм

Вийшла нова версія програми "Склад".


 Виправлено велику кількість помилок.


 Можливість вимкнення заборони негативних чистилів у поточних залишках.


Наші координати

Ел. пошта
rs@corp2.net

Телефон: +38 (067) 901-63-22

Зателефонуйте: +380 63 108 17 00

Напишіть у Telegram: @erpk2

 

Виклик форуму

Динамічна інтернет-сторінка

 


 

Інші посилання


Інші сторінки

Програми
Корпорація

Склад
Корпорація
Бухгалтерія
Зарплата


Програми
Іспит
Розрахунок шаф
Реплікатор
Редактор
VDoc
Календар
Калькулятор
Буфер
Розсилка пошти
Голосування по мережі
Інсталятор
Планувальник
Адміністратор порталу
R-броузер

Документація
Відповіді на запитання
Вся документація
Склад
Розрахунок шаф
Іспит
Реплікатор
Інсталятор

Докумнтація складу
Встановлення програми

Вступ
Введення залишків
Замовлення (купівля)
Заявка
Зовнішній рахунок-фактура
Прихід товару складу
Витрата товару зі складу
Податкова накладна
Внутрішнє переміщення
Списання товару
Повернення товару
Замовлення на закупівлю
Реалізація та консигнація
Відстрочка платежу
Резервування товарів
Рахунок-фактура без рез.
Копіювання документів
Журнали документів
Платіжні документи
Забірний лист
Картка продукції
Калькуляція
Відбраковування товарів
Переоцінка товарів
Бронювання послуг
Анулювання послуг
Рахунок
Журнали документів


Довідник фірм
Довідник активів
Технологічні карти
Прайс-листи
Одиниці виміру
Норми витрати
Місце розташування товару
План рахунків
Сервісні центри
Співробітники
Курси валют
Системні довідники
Фрази

Поточні залишки
Звіт з внутрішнього переміщення
Звіт з продажу
Взаєморозрахунки
Рух матеріалів

Пошук інформації
Штрих-коди, шифри, партії

Об'єднання фірм
Об'єднання товарів
Робота в мережі та інтернет
Визначення прав
Створення та налаштування користувача
Скрипт налаштування користувача
Налаштування фірми
Налаштування складів
Налаштування мов
Типи документів
Налаштування меню
Версії програм та історія
Перевірка розрахунків
Створення та зміна звітів
Створення тіні (дзеркала) бази даних
Відновлення бази даних
Резервне копіювання бази даних

Інформація про програму
Робота з вікнами
Робота з таблицями
Експорт даних у таблицях
Імпорт даних у таблицях
Робота з деревами
Експорт із дизайнера звітів
Опис дизайнера звітів FastReport

Статті
Лічильник
Як заощадити на ліцензіях
Відновлення баз даних Interbase

Послуги
Веб-дизайн
Купівля програм

Інше
Фотогалерея


 

 


Вийшла нова версія програми "Корпорація" (ROffice).

 

 

Переглянути всі новини

 

 

 

 

 








Обмін інформацією по TCP/IP-протоколу

 

Автор: Рудюк С.О.
Internet: rudjuk.kiev.ua

 

Часто виникає необхідність обмінюватися даними між програмами різних комп'ютерах. Наприклад, це необхідно в чатах, або в програмах, які повинні реагувати одночасно на одну й ту саму подію.

Обмін інформації між комп'ютерами можна реалізувати багато способів. У цій статті я розгляну обмін даними за протоколом TCP/IP.

 

Компоненти для обміну даними TCP/IP

Для обміну даними за протоколом TCP/IP будемо використовувати три Indy-компоненти: TIdTCPServer TCP/IP - сервер, TIdTCPClient TCP/IP - клієнт, TIdThreadMgrDefault Потік.

Клієнтська компонента призначена для надсилання та прийому повідомлень, а серверна компонента - для прийому повідомлення та розсилки клієнтським компонентам.

 

Програмна реалізація

Програма складається з двох частин: серверна, на якій стоїть серверна компонента, можна на неї ще поставити і клієнтську компоненту – для тестування клієнтської частини та можливості генерації повідомлень із серверної програми. На клієнтській частині – стоїть лише клієнтська компонента. Ця частина призначена лише для надсилання та прийому повідомлень.

 

Серверна частина

Встановимо на форму у програмі серверної частини компоненти TIdTCPServer TCP/IP - сервер, TIdThreadMgrDefault Потік.

Зв'яжіть властивість ThreadMgr компонентів TIdTCPServer з компонентом TIdThreadMgrDefault.

Для запуску сервера вистачить встановити якість компоненти в True:

Server.Active := True;
Protocol.Lines.Add('=== Запуск сервера ====');

Для зупинки сервера - False:

Server.Active := False;
Protocol.Lines.Add('=== Сервер зупинено====');

Для реєстрації під'єднаного комп'ютера слід визначити подію OnConnect у компоненті TIdTCPServer.

var
NewClient: PClient;

begin
GetMem(NewClient, SizeOf(TClient));

NewClient.DNS := AThread.Connection.LocalName;
NewClient.Connected := Now;
NewClient.LastAction := NewClient.Connected;
NewClient.Thread := AThread;

AThread.Data:=TObject(NewClient);

try
Clients.LockList.Add(NewClient);
finally
Clients.UnlockList;
end;

Protocol.Lines.Add(TimeToStr(Time)+' З'єднання комп'ютера: "'+NewClient.DNS+'"');

end;

Для реєстрації відключення клієнта необхідно визначити подію ServerDisconnect.

var
ActClient: PClient;
ConnN: integer;

begin
ActClient := PClient(AThread.Data);
Protocol.Lines.Add (TimeToStr(Time)+' Від'єднання комп'ютера: "'+ActClient^.DNS+'"');
try
Clients.LockList.Remove(ActClient);
finally
Clients.UnlockList;
end;
FreeMem(ActClient);
AThread.Data := nil;
end;

Обробка команд (розсилання) на серверній частині здійснюється за допомогою події OnExecute.

var
ActClient, RecClient: PClient;
CommBlock, NewCommBlock: TCommBlock;
RecThread: TIdPeerThread;
i, ConnN: Integer;
itmp: integer;


begin
if not AThread.Terminated and AThread.Connection.Connected then
begin


AThread.Connection.ReadBuffer (CommBlock, SizeOf (CommBlock));
ActClient := PClient(AThread.Data);
ActClient.LastAction := Now; // update the time of last action

// Реєстрація комп'ютера
if (RusUpperCase(CommBlock.Command) = RusUpperCase(cmRegisterComp)) then
begin
Protocol.Lines.Add(' Реєстрація комп'ютера: '+RusUpperCase(CommBlock.ComputerName));
meConnected.Lines.Add(RusUpperCase(CommBlock.ComputerName));
RefreshConnected;
RefreshConnectedComps;
RefreshGolosProcess;
// AThread.Connection.WriteBuffer (NewCommBlock, SizeOf (NewCommBlock), true); // and there it goes...
end

// Видалення комп'ютера
else if (RusUpperCase(CommBlock.Command) = RusUpperCase(cmUnRegisterComp)) then
begin
Protocol.Lines.Add(' Видалення комп'ютера: '+RusUpperCase(CommBlock.ComputerName));ConnN

:=FindConnComp(RusUpperCase(CommBlock.ComputerName));
if ConnN<>-1
then meConnected.Lines.Delete(ConnN);

RefreshConnected;
RefreshConnectedComps;
RefreshGolosProcess;
// AThread.Connection.WriteBuffer (NewCommBlock, SizeOf (NewCommBlock), true); // and there it goes...
end

// Реєстрація відповідей
else if (RusUpperCase(CommBlock.Command) = RusUpperCase(cmAnswerQuest)) then
begin
if mdGolos.Locate('CompName',RusUpperCase(CommBlock.Msg),[loCaseInsensitive]) then
begin
mdGolos.Edit;
mdGolosCONN.Value:=True;
mdGolos.Post;
end;

RefreshGolosProcess;
// AThread.Connection.WriteBuffer (NewCommBlock, SizeOf (NewCommBlock), true); // and there it goes...
end

// Різні повідомлення
else if (CommBlock.Command = {'MESSAGE'}cmMess) or (CommBlock.Command = 'DIALOG') then
begin // 'MESSAGE': A message was send - forward or broadcast it
// 'DIALOG': A dialog-window shall popup on the recipient's screen
// it's the same code for both commands...

if CommBlock.ReceiverName = '' then
begin // no recipient given - broadcast
Protocol.Lines.Add (TimeToStr(Time)+' Отримання повідомлення від '
+CommBlock.MyUserName+' '+CommBlock.Command+': "'+CommBlock.Msg+'"');
NewCommBlock := CommBlock; // nothing to change ;-))

with Clients.LockList do
try
for i := 0 to Count-1 do // iterate through client-list
begin
RecClient := Items[i]; // get client-object
RecThread := RecClient.Thread; // get client-thread out of it
RecThread.Connection.WriteBuffer(NewCommBlock, SizeOf(NewCommBlock), True); // send the stuff
end;
finally
Clients.UnlockList;
end;
end
else
begin // receiver given - search him and send it to him
NewCommBlock := CommBlock; // again: nothing to change ;-))
Protocol.Lines.Add(TimeToStr(Time)+' Посилання '+CommBlock.Command+' до "'+CommBlock.ReceiverName+'": "'+CommBlock.Msg+'"');
with Clients.LockList do
try
for i := 0 to Count-1 do
begin
RecClient:=Items[i];
if RecClient.DNS=CommBlock.ReceiverName then // we don't have a login function so we have to use the DNS (Hostname)
begin
RecThread:=RecClient.Thread;
RecThread.Connection.WriteBuffer(NewCommBlock, SizeOf(NewCommBlock), True);
end;
end;
finally
Clients.UnlockList;
end;
end;
end
else
begin // unknown command given
Protocol.Lines.Add (TimeToStr(Time)+' Unknown command from "'+CommBlock.MyUserName+'": '+CommBlock.Command);
NewCommBlock.Command := 'DIALOG'; // the message should popup on the client's screen
NewCommBlock.MyUserName := '[Server]'; // the server's username
NewCommBlock.Msg := 'I don''t understand your command: "'+CommBlock.Command+'"'; // the message to show
NewCommBlock.ReceiverName := '[return-to-sender]'; // unnecessary

AThread.Connection.WriteBuffer (NewCommBlock, SizeOf (NewCommBlock), true); // and there it goes...
end;
end;
end;

Тут я реалізував додаткову реєстрацію комп'ютера за допомогою команди cmRegisterComp='REGISTER', та додатково посилку повідомлення, що комп'ютер відключився: cmUnRegisterComp='UNREGISTER'.

При надсиланні повідомлення передається повідомлення типу TCommBlock. Цей тип даних ми можемо змінювати за потребою. У цьому блоці я оголосив змінну для ідентифікації ComputerName комп'ютера.

TCommBlock = record // the Communication Block used in both parts (Server+Client)
Command,
MyUserName, // the sender of the message
Msg, // the message itself
ReceiverName: string[100]; // name of receiver
ComputerName: String[100]; // Назва комп'ютера, що надсилає повідомлення
end;

Поле Command - команда, яка надсилається з клієнтського місця.
MyUserName - Ім'я користувача, який надсилає повідомлення.
Msg - текст повідомлення.
ReceiverName - назва комп'ютера-отримувача повідомлення, якщо це поле буде порожнім, повідомлення надсилатиметься всім комп'ютерам.

 

Клієнтська частина

Через клієнтську компоненту ми можемо надсилати повідомлення, а також отримувати повідомлення з інших повідомлень.

Встановимо на форму клієнтської програми компоненту TIdTCPClient TCP/IP - клієнт.

Встановимо на форму кнопки Підключитися і Вимкнутись.

Обробник кнопки Підключитися:

IncomingMessages.Lines.Add('===Підключення до сервера===');
Client.Host:=DBInfo.IBaseServerName;
Client.Connect(10000); // in Indy < 8.1 leave the parameter away

ClientHandleThread := TClientHandleThread.Create(True);
ClientHandleThread.Cli:=Client;
ClientHandleThread.EventMest:=FEventMess;
ClientHandleThread.Str:=IncomingMessages.Lines;
ClientHandleThread.FreeOnTerminate:=True;
ClientHandleThread.Resume;

RegComp;

except
on E: Exception do MessageDlg ('Помилка підключення:'+#13+E.Message, mtError, [mbOk], 0);
end;

У кнопці Вимкнутись прописуємо:

if Client.Connected then
begin
ClientHandleThread.Terminate;
Client.Disconnect;
end;

Тип TClientHandleThread призначений для обробки команд із клієнтської сторони.

TEvent_Mesto = procedure(Sender: TObject) of object;
....

TClientHandleThread = class(TThread)
private
procedure HandleInput;
public
Str: TStrings;
Cli: TIdTCPClient;
protected
procedure Execute; override;
public
CB: TCommBlock;
FEventMest: TEvent_Mesto;
published
property EventMest: TEvent_Mesto read FEventMest write FEventMest;
end;
....

var
ClientHandleThread: TClientHandleThread; // variable (type see above)
....

procedure TClientHandleThread.Execute;
begin
while not Terminated do
begin
if not Cli.Connected then
Terminate
else
try
Cli.ReadBuffer(CB, SizeOf (CB));
Synchronize(HandleInput);
except
end;
end;
end;
....

procedure TClientHandleThread.HandleInput;
begin
if Assigned(EventMest) then EventMest(Self);

// Обробка команд
if RusCompare(CB.Command,'MESSAGE') Or (RusCompare(CB.Command,cmdSendPrav)) or (RusCompare(CB.Command, cmdAskPrav)) or
(RusCompare(CB.Command,cmdNewGame)) or (RusCompare(CB.Command,cmdEndGame)) or
(RusCompare(CB.Command,cmdNewTur)) or (RusCompare(CB.Command,cmdEndTur)) or
(RusCompare(CB.Command,cmdRunShellAll)) or (RusCompare(CB.Command,cmdRunShell)) or
(RusCompare(CB.Command,cmdSendActiveWinAll)) or (RusCompare(CB.Command,cmdSendActiveWin)) or
(RusCompare(CB.Command,cmdMinimizeWin)) or (RusCompare(CB.Command,cmdMinimizeWinAll)) or
(RusCompare(CB.Command,cmdCloseWin)) or (RusCompare(CB.Command,cmdCloseWinAll)) or
(RusCompare(CB.Command,cmdSendUserName)) or (RusCompare(CB.Command,cmdSendPassword)) or
(RusCompare(CB.Command,cmdNextGolos)) or (RusCompare(CB.Command,cmdGolosSended)) or
(RusCompare(CB.Command,cmdGolosEkspert)) or (RusCompare(CB.Command,cmdRefreshInfo)) or
(RusCompare(CB.Command,cmdRefreshInfoAll)) or (RusCompare(CB.Command,cmdSendMessage)) or
(RusCompare(CB.Command,cmdSendMessageAll)) or (RusCompare(CB.Command,cmdSendMessageAdmin)) or
(RusCompare(CB.Command,cmdClearMessages)) or (RusCompare(CB.Command,cmdClearMessgesAll)) or
(RusCompare(CB.Command,cmdReconnected)) or (RusCompare(CB.Command,cmdReconnectedAll))
or (RusCompare(CB.Command,cmdSetOcenk))

or RusCompare(CB.Command, cmdRegComp)

then Str.Add (CB.MyUserName + ': ' + CB.Msg)
else
if RusCompare(CB.Command,'DIALOG') then
MessageDlg ('"'+CB.MyUserName+'" посилаємо повідомлення:'+#13+CB.Msg, mtInformation, [mbOk], 0)
else // unknown command
MessageDlg('Команда "'+CB.Command+'" містить це повідомлення:'+#13+CB.Msg, mtError, [mbOk], 0);
end;

...

У процедурі HandleInput перехоплюються повідомлення. У події EventMest ми можемо визначити процедуру, яка буде виконуватись при отриманні повідомлення.

Поміщаємо на форму кнопку Надіслати, поле введення Повідомлення, та список Команда, де буде перераховано всі доступні команди.

В обробнику клацання кнопки опишемо команду посилки повідомлення:

var
CommBlock : TCommBlock;


begin
inherited;

// Команда, яку ми посилаємо
CommBlock.Command := RusUpperCase(EditCommand.Text);

// Назва комп'ютера
CommBlock.MyUserName := Client.LocalName;

// Текст повідомлення
CommBlock.Msg := EditMessage.Text;

// Назва комп'ютера, якому ми надсилаємо повідомлення
CommBlock.ReceiverName := EditRecipient.Text;

// Назва комп'ютера, який надсилає повідомлення
CommBlock.ComputerName := RusUpperCase(Client.LocalName);

Client.WriteBuffer (CommBlock, SizeOf (CommBlock), true);
end;

 

Обговорити на форумі