Board index » cppbuilder » TidTCPclient always disconnects

TidTCPclient always disconnects


2007-08-24 11:42:27 PM
cppbuilder99
Hello,
Using Indy (9.0.50) and C++Builder 2006. I am trying to write
code to poll a TidTCPClient for data. The following code is placed in a timer:
if(!IdTCPClient->Connected())
return;
if(IdTCPClient->IOHandler->Readable(100))
{
try
{
TStringStream* pStream = new TStringStream("");
IdTCPClient->ReadStream(pStream,true);
OutputDebugString(pStream->DataString.c_str());
delete pStream;
}
catch(Exception &e)
{
OutputDebugString(e.Message.c_str());
}
}
However the Client becomes disconnected and I trap the following
exception "Connection Closed Gracefully". I read the article
www.swissdelphicenter.ch/en/showarticle.php
but I cannot see how it related to the above code. Is this not the correct way to poll TidTCPClient?
Thanks in Advance,
Newbie.
 
 

Re:TidTCPclient always disconnects

"newbie" < XXXX@XXXXX.COM >wrote in message
Quote
IdTCPClient->ReadStream(pStream,true);
The second parameter of ReadStream() is an int, not a bool:
void __fastcall ReadStream(TStream *AStream, int AByteCount = -1, const
bool AReadUntilDisconnect = false);
Quote
However the Client becomes disconnected and I trap the
following exception "Connection Closed Gracefully".
That can only happen if the server really is closing the connection after
sending the data. With the code you have, you are telling ReadStream() to
read 1 byte each time it is called, which is wrong. Assuming you wanted to
set the AReadUntilDisconnect parameter to true, then you have to provide a
real value for the AByteCount parameter. You can't use -1 when
AReadUntilDisconnect is true, either. On the other hand, if you are
expecting the server to send the stream size prior to the stream data, then
setting AReadUntilDisconnect to true is wrong.
Quote
Is this not the correct way to poll TidTCPClient?
Your polling is fine. Your reading is not.
Gambit
 

Re:TidTCPclient always disconnects

"Remy Lebeau (TeamB)" < XXXX@XXXXX.COM >wrote in message
Quote
>Is this not the correct way to poll TidTCPClient?

Your polling is fine. Your reading is not.
A better solution is to simply move the reading into a worker thread that
reads in a continue loop instead. Then you don't have to worry about
timeouts or blocking the main thread.
Gambit
 

{smallsort}

Re:TidTCPclient always disconnects

"Remy Lebeau \(TeamB\)" < XXXX@XXXXX.COM >wrote:
Quote

"Remy Lebeau (TeamB)" < XXXX@XXXXX.COM >wrote in message
news:46cf1d6a$ XXXX@XXXXX.COM ...

>>Is this not the correct way to poll TidTCPClient?
>
>Your polling is fine. Your reading is not.

A better solution is to simply move the reading into a worker thread that
reads in a continue loop instead. Then you don't have to worry about
timeouts or blocking the main thread.


Gambit


Thanks for you help Gambit.
This is what I came up with. Hope this what you had in mind?
//header
class TListenThread : public TThread
{
private:
TIdTCPClient* m_pidTCPClient;
typedef void __fastcall (__closure *TListenThreadOnRead)(AnsiString strMessage);
TListenThreadOnRead FOnRead;
void __fastcall ReadEvent();
AnsiString m_strMessage;
protected:
void __fastcall Execute();
public:
__fastcall TListenThread(TIdTCPClient* pClient,
bool CreateSuspended);
__property TListenThreadOnRead OnRead = {read=FOnRead,
write=FOnRead};
};
//source
__fastcall TListenThread::TListenThread(TIdTCPClient* pClient,
bool CreateSuspended)
: TThread(CreateSuspended)
{
m_pidTCPClient = pClient;
}
void __fastcall TListenThread::Execute()
{
//---- Place thread code here ----
TStringStream* pStream;
while (!Terminated)
{
try
{
pStream = new TStringStream("");
m_pidTCPClient->ReadTimeout = 5000;
m_strMessage = "";
m_pidTCPClient->ReadStream(pStream);
m_strMessage = pStream->DataString;
Synchronize(&ReadEvent);
delete pStream;
}
catch(EIdReadTimeout& e)
{
OutputDebugString(e.Message.c_str());
delete pStream;
}
};
}
void __fastcall TListenThread::ReadEvent()
{
if(FOnRead)
FOnRead(m_strMessage);
}
 

Re:TidTCPclient always disconnects

"newbie" < XXXX@XXXXX.COM >wrote in message
Quote
This is what I came up with. Hope this what you had in mind?
Yes. Though you don't need to recreate the stream on each message. You can
reuse it on each loop iteration. And since you are using a TStringStream,
you don't really need the m_strMessage member at all:
typedef void __fastcall (__closure *TListenThreadOnRead)(const
AnsiString &strMessage);
class TListenThread : public TThread
{
private:
TIdTCPClient* m_pidTCPClient;
TStringStream *m_pStream;
TListenThreadOnRead FOnRead;
void __fastcall ReadEvent();
protected:
void __fastcall Execute();
public:
__fastcall TListenThread(TIdTCPClient* pClient);
__fastcall ~TListenThread();
__property TListenThreadOnRead OnRead = {read=FOnRead,
write=FOnRead};
};
__fastcall TListenThread::TListenThread(TIdTCPClient* pClient)
: TThread(true)
{
m_pidTCPClient = pClient;
m_pStream = new TStringStream;
}
__fastcall TListenThread::~TListenThread()
{
delete m_pStream;
}
void __fastcall TListenThread::Execute()
{
while( !Terminated )
{
m_pStream->Size = 0;
try
{
m_pidTCPClient->ReadStream(m_pStream);
}
catch(const EIdReadTimeout &e)
{
OutputDebugString(e.Message.c_str());
continue;
}
catch(const Exception& e)
{
OutputDebugString(e.Message.c_str());
throw;
}
if( FOnRead )
Synchronize(&ReadEvent);
}
}
void __fastcall TListenThread::ReadEvent()
{
if( FOnRead )
FOnRead(m_pStream->DataString);
}
Gambit
 

Re:TidTCPclient always disconnects

"Remy Lebeau \(TeamB\)" < XXXX@XXXXX.COM >wrote:
Quote

"newbie" < XXXX@XXXXX.COM >wrote in message
news:46d2df7d$ XXXX@XXXXX.COM ...

>This is what I came up with. Hope this what you had in mind?

Yes. Though you don't need to recreate the stream on each message. You can
reuse it on each loop iteration. And since you are using a TStringStream,
you don't really need the m_strMessage member at all:

typedef void __fastcall (__closure *TListenThreadOnRead)(const
AnsiString &strMessage);

class TListenThread : public TThread
{
private:
TIdTCPClient* m_pidTCPClient;
TStringStream *m_pStream;
TListenThreadOnRead FOnRead;
void __fastcall ReadEvent();
protected:
void __fastcall Execute();
public:
__fastcall TListenThread(TIdTCPClient* pClient);
__fastcall ~TListenThread();
__property TListenThreadOnRead OnRead = {read=FOnRead,
write=FOnRead};
};


__fastcall TListenThread::TListenThread(TIdTCPClient* pClient)
: TThread(true)
{
m_pidTCPClient = pClient;
m_pStream = new TStringStream;
}

__fastcall TListenThread::~TListenThread()
{
delete m_pStream;
}

void __fastcall TListenThread::Execute()
{
while( !Terminated )
{
m_pStream->Size = 0;

try
{
m_pidTCPClient->ReadStream(m_pStream);
}
catch(const EIdReadTimeout &e)
{
OutputDebugString(e.Message.c_str());
continue;
}
catch(const Exception& e)
{
OutputDebugString(e.Message.c_str());
throw;
}

if( FOnRead )
Synchronize(&ReadEvent);
}
}

void __fastcall TListenThread::ReadEvent()
{
if( FOnRead )
FOnRead(m_pStream->DataString);
}


Gambit


 

Re:TidTCPclient always disconnects

"newbie" < XXXX@XXXXX.COM >wrote:
Quote

"Remy Lebeau \(TeamB\)" < XXXX@XXXXX.COM >wrote:
>
>"newbie" < XXXX@XXXXX.COM >wrote in message
>news:46d2df7d$ XXXX@XXXXX.COM ...
>
>>This is what I came up with. Hope this what you had in mind?
>
>Yes. Though you don't need to recreate the stream on each message. You can
>reuse it on each loop iteration. And since you are using a TStringStream,
>you don't really need the m_strMessage member at all:
>
>typedef void __fastcall (__closure *TListenThreadOnRead)(const
>AnsiString &strMessage);
>
>class TListenThread : public TThread
>{
>private:
>TIdTCPClient* m_pidTCPClient;
>TStringStream *m_pStream;
>TListenThreadOnRead FOnRead;
>void __fastcall ReadEvent();
>protected:
>void __fastcall Execute();
>public:
>__fastcall TListenThread(TIdTCPClient* pClient);
>__fastcall ~TListenThread();
>__property TListenThreadOnRead OnRead = {read=FOnRead,
>write=FOnRead};
>};
>
>
>__fastcall TListenThread::TListenThread(TIdTCPClient* pClient)
>: TThread(true)
>{
>m_pidTCPClient = pClient;
>m_pStream = new TStringStream;
>}
>
>__fastcall TListenThread::~TListenThread()
>{
>delete m_pStream;
>}
>
>void __fastcall TListenThread::Execute()
>{
>while( !Terminated )
>{
>m_pStream->Size = 0;
>
>try
>{
>m_pidTCPClient->ReadStream(m_pStream);
>}
>catch(const EIdReadTimeout &e)
>{
>OutputDebugString(e.Message.c_str());
>continue;
>}
>catch(const Exception& e)
>{
>OutputDebugString(e.Message.c_str());
>throw;
>}
>
>if( FOnRead )
>Synchronize(&ReadEvent);
>}
>}
>
>void __fastcall TListenThread::ReadEvent()
>{
>if( FOnRead )
>FOnRead(m_pStream->DataString);
>}
>
>
>Gambit
>
>

Thanks again.
Your help is greatly appreciated!!
 

Re:TidTCPclient always disconnects

"newbie" < XXXX@XXXXX.COM >wrote in message
Quote
Thanks again.

Your help is greatly appreciated!!
For future reference, please trim your replies.
Gambit