INDY. Data/File transfer using UDP

This is the forum for miscellaneous technical/programming questions.

Moderator: 2ffat

Re: INDY. Data/File transfer using UDP

Postby rlebeau » Fri Aug 21, 2015 3:29 pm

SolodovRD wrote:I need to send some message
Code: Select all
IdTCPServer1->Connection->IOHandler->Write(Message.Length());
IdTCPServer1->Connection->IOHandler->Write(Message);



And which connection are you expecting that to write to? Like TServerSocket, TTcpServer, and jst about any other TCP server component, TIdTCPServer can have multiple connections active at one time. You have to decide which client you want to send to, and then use that client's Connection->IOHandler object. The connections are available in the TIdTCPServer::Contexts property, eg:

Code: Select all
TList *list = IdTCPServer1->Contexts->LockList();
try
{
    TIdContext *ctx = (TIdContext*) list->Items[index of the desired client here];
    ctx->Connection->IOHandler->Write(Message.Length());
    ctx->Connection->IOHandler->Write(Message);
}
__finally
{
    IdTCPServer1->Contexts->UnlockList();
}


That being said, TIdTCPServer is a multi-threaded component (each client runs in its own thread), so you really should be doing all of the writing in the TIdTCPServer::OnExecute() event instead:

Code: Select all
void __fastcall TMyForm::IdTCPServer1Execute(TIdContext *AContext)
{
    ...
    String Message = ...;
    AContext->Connection->IOHandler->Write(Message.Length());
    AContext->Connection->IOHandler->Write(Message);
    ...
}


If you need to send messages from your main UI thread (or any other thread, for that matter), you should give each client its own thread-safe queue of outgoing messages, and then you can push messages into that queue when needed, and have OnExecute() poll messages from that queue periodically. I have demonstrated that technique many many times before in many different forums.

SolodovRD wrote:So, Anyway IdTCPServer not include such method as Write or Writeln


Yes it does, you are just not looking for it in the right place.

SolodovRD wrote:that I seen in several samples in internet. Also it Have no "Connection" method, I found IOHandler, but directly in a IdTCPServer

Like this
Code: Select all
Form1->IdTCPServer1->IOHandler->



That is a different type of IOHandler than you are looking for. You cannot send/receive data using the server's own IOHandler. Its purpose is only to accept client connections. You have to use each client's own IOHandler to exchange data with the clients.

SolodovRD wrote:Also Server and Client have no any method for receiving strings I seen in a samples


Again, yes it does, you are just not looking for it in the right place. You need to use the IOHandler that belongs to the provided TIdContext object:

Code: Select all
class TMemoAddNotify : public TIdNotify
{
private:
    String FMsg;

    __fastcall TMemoAddNotify(const String &AMsg)
        : TIdNotify(), FMsg(AMsg)
    {
    }

protected:
    void __fastcall DoNotify()
    {
        Form1->Memo1->Lines->Add(FMsg);
    }

public:
    static void __fastcall AddToMemo(const String &AMsg)
    {
        (new TMemoAddNotify(AMsg))->Notify();
    }
};

void __fastcall TForm1::IdTCPServer1Execute(TIdContext *AContext)
{
    String S = AContext->Connection->IOHandler->ReadLn(); // or ReadString(), or whatever other Read...() method you need...

    // NOTE: because this event is running in a worker thread, you MUST
    // sync with the main UI thread in order to access UI controls safely...

    //Memo1->Lines->Add(S);
    TMemoAddNotify::AddToMemo(S);
}
Remy Lebeau (TeamB)
Lebeau Software
User avatar
rlebeau
BCBJ Author
BCBJ Author
 
Posts: 1560
Joined: Wed Jun 01, 2005 3:21 am
Location: California, USA

Re: INDY. Data/File transfer using UDP

Postby SolodovRD » Tue Aug 25, 2015 12:41 pm

Thankk you, step-by-step this new things became more clear. Step by step I learning and solve the problem. Information is all I need for understanding.
And if I have Button Click event and function

Code: Select all
void __fastcall TForm1::Button4Click(TObject *Sender)
{
 Something
 I can not use here AContext...
}


I have IdTCPClient component for application that initiate some request / data exchange. So It need to open connection like
Code: Select all
Form1->IdTCPClient1->Connect();


(Host and port set in the properties. Then I will make it using GUI)

So, connection is opened.
Questions:
1. How I can send something (some string for example) to server by Button click? As I mentioned I cannot use AContext inside the ButtonClick function.
2. How I can get IP of connected Client using IdTCPServer (I need it for some data/string sendings to selected client only)
3. How I can to select this client from the connected client list.

4* Can I buy some beer for you? :)
SolodovRD
Active Poster
Active Poster
 
Posts: 12
Joined: Mon Aug 10, 2015 10:45 am

Re: INDY. Data/File transfer using UDP

Postby rlebeau » Tue Aug 25, 2015 6:14 pm

SolodovRD wrote:1. How I can send something (some string for example) to server by Button click? As I mentioned I cannot use AContext inside the ButtonClick function.


TIdTCPClient has its own IOHandler:

Code: Select all
void __fastcall TForm1::Button4Click(TObject *Sender)
{
    IdTCPClient1->IOHandler->Write("Something");
}


SolodovRD wrote:2. How I can get IP of connected Client using IdTCPServer (I need it for some data/string sendings to selected client only)


It is in the AContext->Binding->PeerIP property.

SolodovRD wrote:3. How I can to select this client from the connected client list.


You have to enumerate through the TIdTCPServer::Contexts list looking for the TIdContext object that belongs to the desired client.
Remy Lebeau (TeamB)
Lebeau Software
User avatar
rlebeau
BCBJ Author
BCBJ Author
 
Posts: 1560
Joined: Wed Jun 01, 2005 3:21 am
Location: California, USA

Re: INDY. Data/File transfer using UDP

Postby SolodovRD » Tue Sep 01, 2015 12:00 pm

No any "Execute" event for client. No such function as
Code: Select all
void __fastcall TForm1::ChatClientExecute(TIdContext *AContext)


If the server sends some message as
Code: Select all
Form1->IdTCPServer1->IOHandler->Write(SendT.Length());
      Form1->IdTCPServer1->IOHandler->Write(SendT);


How Client can accept it?
SolodovRD
Active Poster
Active Poster
 
Posts: 12
Joined: Mon Aug 10, 2015 10:45 am

Re: INDY. Data/File transfer using UDP

Postby rlebeau » Tue Sep 01, 2015 3:55 pm

SolodovRD wrote:No any "Execute" event for client. No such function as
Code: Select all
void __fastcall TForm1::ChatClientExecute(TIdContext *AContext)



No. TIdTCPClient is not a multi-threaded component. The typical usage is to simply write your outgoing command as needed and then immediately read the response as needed. If you want to do the reading asynchronously, you will have to use a separate thread or timer for that.

SolodovRD wrote:If the server sends some message as
Code: Select all
Form1->IdTCPServer1->IOHandler->Write(SendT.Length());
Form1->IdTCPServer1->IOHandler->Write(SendT);



You can't write data to a TIdTCPServer like that. I showed you earlier how to do it correctly. You need to either move your writing logic into the OnExecute event (where it belongs) or use the TIdTCPServer.Contexts list. Either way will give you access to the appropriate TIdContext object whose IOHandler you can then write data to.

SolodovRD wrote:How Client can accept it?


I think you need to read Indy's documentation, especially its introduction.
Remy Lebeau (TeamB)
Lebeau Software
User avatar
rlebeau
BCBJ Author
BCBJ Author
 
Posts: 1560
Joined: Wed Jun 01, 2005 3:21 am
Location: California, USA

Previous

Return to Technical

Who is online

Users browsing this forum: Bing [Bot] and 14 guests