Як отримати повідомлення від TCPServera

Проблема така надсилаю повідомлення на сервер procedure TForm1.BitBtn1Click(Sender: TObject); begin IdTCPClient1.WriteLn('М'+Memo2.Text); end; на сервері обробник if Msg[1]="M" then begin BroadcastMessage("E", "New Message"); End; Як клієнту отримати це повідомлення, робити ReadLn за таймером ?

procedure TForm1.BitBtn1Click(Sender: TObject); var Response : string; begin IdTCPClient1.WriteLn('М'+Memo2.Text); Response:=IdTCPClient1.ReadLn;>end;

а якщо клієнтів 2, то другий отримує повідомлення, лише надіславши запит серверу. як зробити що б він автоматично прийняв? тобто один послав, на решті клієнтів відбилося?

Клієнт посилає повідомленнясерверу, а не іншим клієнтам. Щоб інші клієнти побачили повідомлення потрібно, щобсервервідправив це повідомлення цим клієнтам

та хоч 2 мільйони!

> другий отримує повідомлення, тільки надіславши запит серверу

це щодо [1] ? не потрібно інтерпретувати ПРИКЛАД настільки буквально.

Як можна надіслати повідомлення від сервера до клієнта? Щось я ніде таких прикладів не знаходжу

> Щось я ніде таких прикладів не знаходжу

ну зрозуміло. а набрати в довідці по Інді-компонентам, наприклад, ключ. слово "WriteLn" та подивитися, які Інді-класи мають цей метод - не царська ця справа.

Чесно дивився, але якщо клієнт відправить серверу повідомлення WriteLn, то клієнт отримає його тільки опитавши сервер, так?

Якщо відповідальний відповість на запитання запитувача, то запитувач знатиме відповідь тільки почувши відповідача. Так? Чи, може, інакше?

немає питання в іншому як здійснити широковажливе повідомлення, тобто, наприклад, один клієнт послав серверу повідомлення, і про цевідразу повинні знати всі клієнти під'єднані до серверу. Робити це за таймером опитувати всім сервер, або ставити TCP клієнт і TCP сервер на одну програму?

Я реалізував це по таймеру, тобто. після надсилання повідомлення на сервер (IdTCPServer) мій клієнт чекає 1,5 секунди (як сказала одна панночка: "Шоб на верняка"), а потім приймає інформацію від сервера. Щодо сервера. У нього є подія OnExecute(AThread: TIdPeerThread), де AThread ОДНОЗНАЧНО ІДЕНТИФІКУЄ джерело отримання інформації (IdTCPClient"а, коротше). А тому, вішаєш на цю подію потрібний тобі код і вперед. купа будь-яких властивостей, Наприклад - Connection (з'єднання, що викликало метод OnExecute). У нього є методи Write.(написати клієнту) і Read.(прочитати від клієнта).Так що успіхів.

До чого тут таймер? Навіщо він?

А про те, що треба зробити, щоб усі клієнти отримали повідомлення першого клієнта тобі вже сказали.

об'єкт TIdTCPServer має св-во Threads: TThreadList, це список об'єктів класу TIdPeerThread, кожен з яких асоційований з активним клієнтом

об'єкт TIdPeerThread має св-во Connection: TIdTCPServerConnection

об'єкт Connection має метод WriteLn()

добре ось такий код відправить повідомлення все підключеним на даний момент клієнтам? procedure TForm1.IdTCPServer1Execute (AThread: TIdPeerThread); Count: Integer; begin Msg := AThread.Connection.ReadLn; для Count := 0 до IdTCPServer1.Threads.LockList.Count -1 до TIdPeerThread(IdTCPServer1.Threads.LockList.Items[Count]).Connection.WriteLn(Msg); IdTCPServer1.Threads.UnlockList;

procedure TForm1.IdTCPServer1Execute(AThread: TIdPeerThread); var i: Integer; Msg : string; begin Msg:= AThread.Connection.ReadLn; з AThread.Connection.Server.Threads.LockList до до для i := 0 до Count -1 до до TIdPeerThread(Items[i]).Connection.WriteLn( Msg); except end; finally IdTCPServer1.Threads.UnLockList; end; end;

далі запустив два клієнти, один набрав повідомлення і натиснув кнопку procedure TForm1.BitBtn1Click(Sender: TObject); var Response : string; begin IdTCPClient1.WriteLn(Memo2.Text); Response:=IdTCPClient1.ReadLn; end; отримав відразу ж відгук, другий сидить нічого не отримавши. Або отримав та я не зміг обробити прийом?

> отримав відразу ж відгук

правильно, отримав .. бо IdTCPClient1.ReadLn виконав

а той (інший) клієнт, який у цей момент "бив байдики", не викликаючи IdTCPClient1.ReadLn, зрозуміло, нічого не отримав.. а з якого переляку він щось отримати мав. якщо навіть пальцем не поворухнув? законнектився і сидить собі чекає біля моря погоди?

"Запитує і отримає відповідь"(с)

Коли і коли другому клієнту треба викликати IdTCPClient1.ReadLn, опитувати сервер через проміжки часу?

> Коли і коли другому клієнту треба викликати IdTCPClient1.ReadLn

у той момент, коли цей клієнт бажає отримати рядкове повідомлення, що потенційно надсилається сервером

> опитувати сервер через проміжки часу?

це ще навіщо? ти розраховуєш щось отримати від сервера? ну так і викликай ReadLn()! Як тільки сервер спроможеться тобі щось надіслати, ф-ція поверне управління і поверне результуючу отриману від сервера рядок

У прикладах DELPHI є програма NETCHAT ось там на формі лежить як клієнтський компонент так і серверний

> Anton.(10.06.04 11:47) [19] > У прикладах DELPHI є програма NETCHAT там на формі > лежить як клієнтський компонент і серверний

І що?> Anton. (10.06.04 11:38) [17] > Коли і коли другому клієнту треба викликати IdTCPClient1.ReadLn, > опитувати сервер через проміжки часу?

Та не сервер опитувати! А свій сокет, підключений до сервера. Хоч через проміжки часу, хоч в окремому потоці, хоч відразу ж і readln роби, а на форму кинь antifreez. Справа смаку і відповідності задачі. Але, IdTCPClient не має можливості асинхронно, самостійно повідомити, що в його сокеті з'явилися якісь прийняті дані.

що начебто вийшло, ваші оцінки?

procedure TForm1.FormCreate(Sender: TObject); var MyThread: TThread; begin IdTCPClient1.Connect; T1 := TMyThread1.Create(False); T1.Priority := tpLowest; end;

procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction); begin IdTCPClient1.Disconnect; end;

procedure TForm1.BitBtn2Click(Sender: TObject); begin close; end;

procedure TForm1.ListenServer; begin Memo1.Text:=IdTCPClient1.ReadLn; end;

procedure TForm1.BitBtn1Click(Sender: TObject); begin IdTCPClient1.WriteLn("M"+Memo2.Text); Memo2.Clear; ListenServer; end;

procedure TMyThread1.Execute; begin якщо не є Terminated do Synchronize(DoWork); end;

procedure TMyThread1.DoWork; begin Form1.ListenServer; end;

за абсолютно бездумне здирання коду методу TMyThread1.Execute;

> [21] Anton. (10.06.04 17:56) > що начебто вийшло, ваші оцінки? > > procedure TForm1.FormCreate(Sender: TObject); > var >MyThread: TThread; > початок > Memo2.Clear; > IdTCPClient1.Connect; > T1 := TMyThread1.Create(False); > end; > > procedure TForm1.FormClose(Sender: TObject; var Action: > TCloseAction); > початок > IdTCPClient1.Disconnect; > end; > > процедура TForm1.BitBtn2Click(Відправник: TObject); > початок > закрити; > end; >

> процедура TForm1.BitBtn1Click(Відправник: TObject); > початок > IdTCPClient1.WriteLn("M"+Memo1.Text); > end; > > процедура TMyThread1.Execute; > початок > поки не завершено do begin NewS := IdTCPClient1.ReadLn; якщо NewS <> "" потім Синхронізувати(Show_NewS); кінець; > end; > > процедура TMyThread1.Show_NewS; > begin Memo1.Lines.Add(NewS); > кінець;

NewS : рядок; - поле TMyThread1

P.S. А де народ берет цей шаблон Execute: while not Terminated do Synchronize(DoWork) ? P.P.S. Эта "рыба" погано пахнет.

Спасибо ошибки понял, учту

некто Карих Микола в свое время подсуетился неудачно . хотя . звинувачувати його у всіх смертних грехах теж вроде би немає приводу - там адже в статті як раз слово "шаблон" явно фігурує .

Может я не доганяю, але клієнт на то і клієнт що б спращивать. ІМХО сервер не може довільно надіслати клієнту дані. Просто клієнт не запитує порт, лише на час тайм-ауту, очікує відповідь на сервер. Можна звичайно і порт слухати і коннект ловити, але це вже допоможе сервер, а не клієнт.

колька (12.06.04 23:44) [26]

сервер може надіслати повідомлення клієнту, наприклад, за надходженням повідомлення від іншого клієнта. Це повідомлення потрапляє в пункт призначення і сидить в стеці TCP і жде, коли тамошній клент його запропонує, виповнивReadLn наприклад. Коли TIdTcpClient робить ReadLn, він звертається саме до локального TCP стеку, а не до сервера. .д.). Наприклад раз на 200 мілісекунд. Обов'язково ставте на форму TIdAntifreeze, одне на додаток, інакше форма буде "заморожуватися", оскільки Indy сокети працюють у блокувальному режимі. Якщо ви використовуєте TIdTcpServer і щось хочете відмалювати на формах подію OnExecute, то обов'язково робіть Synchronize() або використовуйте для цієї справи TIdSync. Той самий принцип і для роботи з базою даних. Створюйте/знищуйте екземпляр датамодуля при кожному запиті або використовуйте єдиний датамодуль, проставляючи критичні секції або створюйте пул датамодулів та регулюйте їх видачу тредам семафорами. Точніше не дата модулів, а наборів dbconnection+dbqueries.

alienserg (14.06.04 2:44) [27] >Це повідомлення потрапляє в пункт призначення і сидить у TCP стеку і >жде, коли тамтешній клент його опитає, виконавши ReadLn >наприклад .

Клієнту все-таки доведеться опитати сервер. Тоді можна зробити ось так: клієнт (по таймеру) опитує сервер щодо появи для нього(клієнта) нового повідомлення. client1.SendCmd("numb"); if client1.LastCmdResult.Text.Text = "ok" then readin(buf); Сервер. var mess: boolean; procedure TForm1. Server1Command1numb(ASender: TIdCommand); WriteLn("потрібний рядок); end else begin exit; end;

У else кидай asender.Thread.Connection.WriteLn("no"); у клеенті обробник: case if client1.LastCmdResult.Text.Textof "ok":readin(buf); "no":exit;

if client1.LastCmdResult.Text.Text = "ok" then змінити на if client1.readln = "ok" then

Коли TIdTcpClient робить ReadLn, він звертається до внутрішнього буфера Indy. Тому, читаючи без затримки (не чекаючи відправки серверу), легко можна вважати своє ж повідомлення, надіслане серверу тим самим клієнтом перед цим через TIdTcpClient.WriteLn!

Петров (15.06.04 13:31) [31]

буфери для ReadLn і WriteLn різні.FInputBuffer: TIdManagedBuffer; FWriteBuffer: TIdSimpleBuffer;