Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Сети";
Текущий архив: 2004.08.22;
Скачать: [xml.tar.bz2];

Вниз

Как получить сообщение от TCPServera?   Найти похожие ветки 

 
Anton.   (2004-06-09 16:06) [0]

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


 
Reindeer Moss Eater ©   (2004-06-09 16:32) [1]

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


 
Anton.   (2004-06-09 17:12) [2]

а если клиентов 2, то второй получает сообщение, только послав запрос серверу. как сделать что бы он автоматом принял? т.е один послал, на всех остальных клиентах отразилось?


 
Reindeer Moss Eater ©   (2004-06-09 17:25) [3]

Клиент посылает сообщение серверу, а не другим клиентам.
Что бы другие клиенты увидели сообщение нужно чтобы сервер отправил это сообщение этим клиентам


 
Digitman ©   (2004-06-09 17:31) [4]


> а если клиентов 2


да хоть 2 миллиона !


> второй получает сообщение, только послав запрос серверу


это в отношении [1] ? не нужно интерпретировать ПРИМЕР столь буквально ...


 
Anton.   (2004-06-09 18:04) [5]

Как можно отправить сообщение от сервера к клиенту? Что то я нигде таких примеров не нахожу


 
Digitman ©   (2004-06-10 08:20) [6]


> Что то я нигде таких примеров не нахожу


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


 
Anton.   (2004-06-10 08:50) [7]

Чесно смотрел, но если клиент отправит серверу сообщение WriteLn, то клиент его получит только опросив сервер, так?


 
Reindeer Moss Eater ©   (2004-06-10 09:33) [8]

Если отвечающий ответит на вопрос спрашивающего, то спрашивающий будет знать ответ только услышав отвечающего.
Так? Или может иначе?


 
Anton.   (2004-06-10 09:49) [9]

нет вопрос в другом как осуществить широковешательное сообщение, то есть например один клиент послал серверу сообщение, и об этом сразу же должны знать все клиенты подсоедененные к серверу. Делать это по таймеру опрашивать всем сервер, или ставить TCP клиент и TCP сервер на одно приложение?


 
Artem03   (2004-06-10 09:54) [10]

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


 
Reindeer Moss Eater ©   (2004-06-10 09:55) [11]

При чем здесь таймер?
Зачем он?

А про то, что надо сделать что бы все клиенты получили сообщение первого клиента тебе уже сказали.


 
Digitman ©   (2004-06-10 10:15) [12]


> Anton.   (10.06.04 09:49) [9]


объект TIdTCPServer  имеет св-во Threads: TThreadList, это список объектов класса TIdPeerThread, каждый из которых ассоциирован с активным клиентом

объект TIdPeerThread имеет св-во Connection:  TIdTCPServerConnection

объект Connection имеет метод WriteLn()


 
Anton.   (2004-06-10 10:54) [13]

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


 
Digitman ©   (2004-06-10 11:05) [14]

procedure TForm1.IdTCPServer1Execute(AThread: TIdPeerThread);
var
i: Integer;
Msg : string;
begin
Msg    := AThread.Connection.ReadLn;
with AThread.Connection.Server.Threads.LockList do
try
 for i := 0 to Count -1 do
  try
   TIdPeerThread(Items[i]).Connection.WriteLn(Msg);
  except
  end;
finally
  IdTCPServer1.Threads.UnLockList;
end;
end;


 
Anton.   (2004-06-10 11:16) [15]

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


 
Digitman ©   (2004-06-10 11:23) [16]


> получил сразу же отклик


правильно, получил ..
потому что IdTCPClient1.ReadLn выполнил

а тот (другой) клиент, который в этот момент "бил баклуши", не вызывая IdTCPClient1.ReadLn, разумеется, ничего не получил .. а с какого перепугу он что-то получить должен был. если даже пальцем не пошевелил ? законнектился и сидит себе ждет у моря погоды ?

"спрашивающий да получит ответ"(с)


 
Anton.   (2004-06-10 11:38) [17]

Когда и в какой момент второму клиенту надо вызывать IdTCPClient1.ReadLn, опрашивать сервер через промежутки времени?


 
Digitman ©   (2004-06-10 11:47) [18]


> Когда и в какой момент второму клиенту надо вызывать IdTCPClient1.ReadLn


в тот момент, когда этот клиент желает получить  потенциально отправляемое сервером строковое сообщение


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


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


 
Anton.   (2004-06-10 11:47) [19]

В примерах DELPHI есть программка NETCHAT вот там на форме лежит как клиентский компонент так и серверный


 
Verg ©   (2004-06-10 11:56) [20]


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


Ну и что?

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


Да не сервер опрашивать! А свой сокет, подключенный к серверу.
Хоть через промежутки времени, хоть в отдельном потоке, хоть сразу же и readln делай, а на форму кинь antifreez... Дело вкуса и соответствия задаче.
Но, IdTCPClient не имеет возможности асинхронно, самостоятельно сообщить, что в его сокете появились какие-то принятые данные.


 
Anton.   (2004-06-10 17:56) [21]

что то вроде получилось, ваши оценки?

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
 while not Terminated do
  Synchronize(DoWork);
end;

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


 
Digitman ©   (2004-06-10 18:02) [22]


> ваши оценки?


твердый кол

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


 
Verg ©   (2004-06-10 18:14) [23]


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

> procedure TForm1.BitBtn1Click(Sender: TObject);
> begin
>  IdTCPClient1.WriteLn("M"+Memo1.Text);
> end;
>
> procedure TMyThread1.Execute;
> begin
>  while not Terminated do
   begin
      NewS := IdTCPClient1.ReadLn;
      if NewS <> "" then
        Synchronize(Show_NewS);
   end;
> end;
>
> procedure TMyThread1.Show_NewS;
> begin
     Memo1.Lines.Add(NewS);
> end;


NewS : string; - поле TMyThread1

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


 
Антон.   (2004-06-10 18:29) [24]

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


 
Digitman ©   (2004-06-11 08:18) [25]


> Verg ©   (10.06.04 18:14) [23]


> где народ берет этот шаблон Execute


ну где ж ? разумеется, здесь же , в статьях...

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


 
колька   (2004-06-12 23:44) [26]

Может я не доганяю, но клиент на то и клиент что б спращивать.
ИМХО сервер никак не сможет произвольно послать клиенту дату. Просто клиент не опрашивает порт, лишь на время timeout`а, ожидая ответ сервера. Можно конечно и порт слушать и коннект ловить, но это помоему уже будет сервер, а не клиент.


 
alienserg   (2004-06-14 02:44) [27]

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

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


 
колька   (2004-06-14 03:47) [28]

alienserg  (14.06.04 02:44) [27]
>Это сообщение попадает в пункт назначения и сидит в TCP стеке и
>ждет, когда тамошний клент его опросит, выполнив ReadLn
>например.

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


 
колька   (2004-06-14 03:54) [29]

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


 
колька   (2004-06-14 04:37) [30]

if client1.LastCmdResult.Text.Text = "ok" then
поменять на
if client1.readln = "ok" then


 
Петров   (2004-06-15 13:31) [31]

Когда TIdTcpClient делает ReadLn, он обращается к внутреннему буферу Indy. Поэтому, читая без задержки (не дожидаясь отправки серверу), легко можно считать свое же сообщение, посланное серверу тем же самым клиентом перед этим через TIdTcpClient.WriteLn!


 
alienserg   (2004-06-18 02:40) [32]

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

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


 
Петров   (2004-06-22 17:53) [33]

Да, признаю свою ошибку.



Страницы: 1 вся ветка

Форум: "Сети";
Текущий архив: 2004.08.22;
Скачать: [xml.tar.bz2];

Наверх




Память: 0.54 MB
Время: 0.031 c
14-1091609155
Ricko
2004-08-04 12:45
2004.08.22
SMS голосование


6-1087790121
Сергей Г
2004-06-21 07:55
2004.08.22
E-Mail


1-1091689868
tria
2004-08-05 11:11
2004.08.22
Как при закрытии приложения вызвать OnClose дочерних mdi-форм?


3-1091347786
viktor
2004-08-01 12:09
2004.08.22
field "XXX" not found


3-1091013683
Klerk
2004-07-28 15:21
2004.08.22
Доступ к FireBird





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский