Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C++ Builder > Indy 10, Server -> Client


Автор: CaLaT 28.3.2009, 22:19
Долго пытался разобраться, но, ну никак, не получается. Разбираюсь в Indy 10, Builder 2007
Суть - есть сервер, есть клиенты. Клиенты приконнектились, и просто сидят ждут, когда сервер в ему угодное время отправит что-либо. Так вот. Как клиентом серверу сообщения посылать я понял, а вот как сервер клиенту должен послать я так и не понял.

Большая просьба помчь строчкой кода ввиде примера.

Автор: SVN74 29.3.2009, 00:00
Цитата(CaLaT @  28.3.2009,  22:19 Найти цитируемый пост)
Так вот. Как клиентом серверу сообщения посылать я понял, а вот как сервер клиенту должен послать я так и не понял.

Client ----->>>>> "OK"
Server ------->>>>> "NoOK"
======================
Сервер посылает в созданном потоке (при соединении с клиентом) ответ....

Автор: CaLaT 29.3.2009, 00:11
Допустим, я могу сразу ответить клиенту например так:

Код

void __fastcall TMForm::ServerConnect(TIdContext *AContext)
{
    String Cmd;
    Cmd=Trim(AContext->Connection->IOHandler->ReadLn());

    if (AnsiSameText(Cmd, "Help"))
        AContext->Connection->IOHandler->WriteLn('OkiDoki');

}


но как я смогу ответить вне функций ОнКоннект и ОнЭкзекьют, ведь там-то у меня не будет передаваемого *AContext? Ну в смысле, где в объекте TIdTCPServer хранятся указатели на подключенных клиентов?

За ранее пасибо!

Автор: SVN74 29.3.2009, 00:18
Вот отдельное событие (отдельный поток)
====================================================
void __fastcall TForm1::IdTCPServer1Execute(TIdContext *AContext)
{
   try
   {
     Тут обслуживаем клиента, если надо сделаем задержку

   }
   __finally
   {
       AContext->Connection->Disconnect();
   }
}

Автор: CaLaT 29.3.2009, 08:29
Цитата(CaLaT @  29.3.2009,  00:11 Найти цитируемый пост)
но как я смогу ответить вне функций ОнКоннект и ОнЭкзекьют, ведь там-то у меня не будет передаваемого *AContext? Ну в смысле, где в объекте TIdTCPServer хранятся указатели на подключенных клиентов?



Цитата(SVN74 @  29.3.2009,  00:18 Найти цитируемый пост)
void __fastcall TForm1::IdTCPServer1Execute(TIdContext *AContext)


Как из функции Execute и других у объекта IdTCPServer сделать ответ клиенту я понял, ну а как это сделать скажем из функции Баттон1? Или ты хочешь сказать что это не возможно и нужно делать задержки в функции экзекьют? Это же такое геморрой  smile

Добавлено через 6 минут и 12 секунд
Допустим в TcpServer's инфа о подключенных хранилась в  TcpServer->Socket->Connections[index], неужели нет аналога у IdTCPServer? 

Автор: SVN74 29.3.2009, 11:43
Цитата(CaLaT @  29.3.2009,  08:29 Найти цитируемый пост)
ну а как это сделать скажем из функции Баттон1? Или ты хочешь сказать что это не возможно и нужно делать задержки в функции экзекьют? Это же такое геморрой  

Да, нужно делать задержку для клиента, (правда, если количество клиентов не очень большое), а Button1 -> это общий ресурс, соответственно в потоке TForm1::IdTCPServer1Execute (через синхронизацию) просто надо отслеживать изменения состояния (к примеру) глобальной переменной и делать определенные выводы и причем это не затронет основной поток, и не будет видно ни каких задержек...

Автор: CaLaT 29.3.2009, 12:48
Ладно, попытаюсь реализовать... хотя назвать это удобным, мегко говоря, не получается.
И еще вопрос - если допустим у меня 4и клиента находяцца на коннекте (из функции Экзекьют я уже вышел) и мне надо его отдесконектить, то как обраться именно к 3ему клиенту и скачать ему "пока"? 

Автор: SVN74 29.3.2009, 17:15
Попробуй так:
===================
AContext->Connection[0].IOHandler->WriteLn("Bla, Bla");
===================
Можно еще так:
==========================
IdTCPServer1->Bindings->Items[0]->Collection->Count;
IdTCPServer1->Bindings->Items[0]->........
==========================
Надо пробовать всевозможные варианты...

==================================================
Вообще лучше использовать WinSock (без гмр.)

Автор: CaLaT 30.3.2009, 08:42
Код

procedure TForm1.Button1Click(Sender: TObject);
begin
if IdTCPServer.Contexts <> nil then
  begin
    with IdTCPServer.Contexts.LockList do try
        TIdContext(Items[i]).Connection.IOHandler.Writeln('Hello');
    finally
      IdTCPServer.Contexts.UnLockList;
    end;
  end;
end;
------------------------------------------------
TIdContext(Items[i]).Connection.Socket.Binding.PeerIP
TIdContext(Items[i]).Connection.Socket.Binding.PeerPort
Покажет откуда к тебе подключились, если произошел сдвиг  
------------------------------------------------
TIdContext(Items[i]).Connection.Disconnect(False);


Пытался работать с этим в си и у меня не получается привести Server->Contexts->LockList()->Items[0] (void*) к типу TIdContext... есть мысли?

Автор: CaLaT 30.3.2009, 18:20
Цитата(CaLaT @  30.3.2009,  08:42 Найти цитируемый пост)
не получается привести Server->Contexts->LockList()->Items[0] (void*) к типу TIdContext


Сделал так:
Код

    ShowMessage(Server->Contexts->LockList()->Count);
    TIdContext *Context=static_cast<TIdContext *>(Server->Contexts->LockList()->Items[0]);
    Context->Connection->Socket->WriteLn("Send You Hello!");
    Server->Contexts->UnlockList();


И вот только теперь я заметил что у объекта TIdTCPClient нет метода OnRead() или OnReceive(). Каким образом мне понять что сервер что-то засылает?

пс: я надеюсь, для этого не потребуется в цикле проверять

Добавлено через 3 минуты и 4 секунды
Просьба не предлогать проверять в ручную, всё таки эта будет лишняя нагрузка, которая кленту не нужна

Автор: Anikmar 30.3.2009, 18:41
Цитата(CaLaT @  30.3.2009,  18:20 Найти цитируемый пост)
И вот только теперь я заметил что у объекта TIdTCPClient нет метода OnRead() или OnReceive(). Каким образом мне понять что сервер что-то засылает?

Так там вроде запихнуто все в одно событие OnWork. Или я ошибаюсь?

Автор: CaLaT 30.3.2009, 19:13
К сажелению событие ОнВорк несрабатывает... вообще никогда. Хотя если вручную проверить, то сообщение отправленное сервером на сокете есть.

Автор: CaLaT 30.3.2009, 22:06
Даже ОнСтатус возвращающий стринги с текущими действиями не реагирует на сообщения от сервера

Автор: SVN74 30.3.2009, 23:52
WinSock просто и надежно...

Автор: CaLaT 12.4.2009, 18:33
Так и не нашёл...
Пришлось реализовать через tplower поток, который мониторит сокет на появление данных

Еще вопрос:
При передачи достаточно больших файлов, хотелось бы юзеру сообщать об общем ходе передачи на стороне клиента. 
Нашёл переменную - WriteBufferThreshhold , которая по идеи и должна возвращать желанное. Но получаю почему-то только -1.

Автор: CaLaT 15.4.2009, 08:47
Передачу делаю так:
Код

 TransmiteFile = new TMemoryStream ();

 try
 {
  TransmiteFile->LoadFromFile(OpenDialog->FileName.c_str());
 }
 catch(...)
 {
  //...
 } 
 Client->Socket->SendBufferSize=TransmiteFile->Size;
 Client->Socket->WriteBufferOpen();
 Client->Socket->Write(TransmiteFile,TransmiteFile->Size,false);
 Client->Socket->WriteBufferClose();
 delete TransmiteFile;


До передачи организую отдельный поток, который должен считывать сколько передано, но...
TransmiteFile->Position всегда на конечном кол-во байт, (т.е =TransmiteFile->Size) а если Position в ручную обнулить перед передачей, то он всегда будет 0
Client->Socket->WriteBufferThreshhold  всегда = -1

Помогите пожалуйста! Может я что-то делаю не так, или не то?

Автор: CaLaT 18.4.2009, 11:05
Может попробовать разбивать Мэмористрим на небольшие части и отправлять их частями? сколько частей будет я знаю и знаю по сколько эти части...
Блин, чото это на изобретение велосипеда тянет... мож таки есть другие решения? ...мысли?

Автор: artsb 18.4.2009, 21:50
хотя я и не профи в Indy...
Не совсем понял, почему вы отправляете файл именно так. Есть же метод WriteStream.
Но это в 8-ой версии. 10-я вроде как претерпела большие изменения. Так что может вы и правы.

Цитата(CaLaT @  18.4.2009,  11:05 Найти цитируемый пост)
Может попробовать разбивать Мэмористрим на небольшие части и отправлять их частями? сколько частей будет я знаю и знаю по сколько эти части...

Наверное, это единственный выход...

Автор: artsb 18.4.2009, 22:15
Цитата(CaLaT @  30.3.2009,  18:20 Найти цитируемый пост)
И вот только теперь я заметил что у объекта TIdTCPClient нет метода OnRead() или OnReceive(). Каким образом мне понять что сервер что-то засылает?

Это можно делать где угодно. Например, в Button1Click:
Код

idClient1->Connect();
idClient1->Write...;
idClient1->Read...;
idClient1->Disconnect();

Естественно, не забываем про try catch.

А событие OnWork наступает, когда происходит запись или чтение данных. AWorkMode показывает, что сейчас происходит (запись или чтение), а AWorkCount содержит количество переданных/прочитанных байт.

Событие OnBeginWork наступает перед записью/чтением. AWorkMode показывает, что сейчас происходит (запись или чтение), а AWorkCountMax в случае чтения, содержит количество байт, которые будут приниматься.

Автор: CaLaT 20.4.2009, 21:18
Ох и замучался я с этой десяткой(

Цитата(artsb @  18.4.2009,  21:50 Найти цитируемый пост)
Не совсем понял, почему вы отправляете файл именно так. Есть же метод WriteStream.


Цитата(artsb @  18.4.2009,  22:15 Найти цитируемый пост)
Это можно делать где угодно. Например, в Button1Click:

код C++ Builder
idClient1->Connect();
idClient1->Write...;
idClient1->Read...;
idClient1->Disconnect();

Всё верно, но только не для 10ой инди( Её переработали(


Цитата(artsb @  18.4.2009,  22:15 Найти цитируемый пост)
А событие OnWork наступает, когда происходит запись или чтение данных. AWorkMode показывает, что сейчас происходит (запись или чтение), а AWorkCount содержит количество переданных/прочитанных байт.

Событие OnBeginWork наступает перед записью/чтением. AWorkMode показывает, что сейчас происходит (запись или чтение), а AWorkCountMax в случае чтения, содержит количество байт, которые будут приниматься. 

По описанию так и должно быть, но проблема с том, что событие ОнВорк() вообще не срабатывает. Я даже пытался его прораммно вызывать:
Код

Client->Socket->BeginWork(wmWrite, 0);
Client->Socket->DoWork(wmWrite,MForm->TransmiteFile->Size);
Client->Socket->Write(MForm->TransmiteFile,MForm->TransmiteFile->Size,false); //отправка
Сlient->Socket->EndWork(wmWrite);
//TransmiteFile - МемориСтрим

В это случаи функция ОнВорк Срабатывает, но вызывается единожды... Как только не пробовал(


Автор: artsb 21.4.2009, 00:19
Цитата(CaLaT @  20.4.2009,  21:18 Найти цитируемый пост)
событие ОнВорк() вообще не срабатывает

Странно, у меня срабатывает...

ЗЫ видать 10-ка серьёзные изменения притерпела...

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)