Mega Search
23.2 Million


Sign Up

Make a donation  
TTcpClient Connected property always indicates false  
News Group: embarcadero.public.cppbuilder.internet.socket

Hi all,
I'm using the TTcpClient class in C++Builder XE2.
As soon as I set the Active property to true, I can trace (via wireshark) the TCP syn/syn ack sequence.
This tells me that there IS a TCP connection active. The connected property however always indicates false.

if( TcpClient == NULL)
   TcpClient = new TTcpClient(NULL); // Now own TcpClient 

DWORD CIpIo::Open(int DeviceNumber, HDEVINFO DeviceList, const GUID* InterfaceGuid)
{
	if( !IPClient->Active) {
		IPClient->Active = true;
		Sleep(250); // Give TSEC server time to stack it's protocols....
	}
	return(0);
}

Any suggestions?
Thanx....

#TTcpClient #builder

Vote for best question.
Score: 0  # Vote:  0
Date Posted: 8-Sep-2014, at 1:10 AM EST
From: rene v.d. berge
 
Re: TTcpClient Connected property always indicates false  
News Group: embarcadero.public.cppbuilder.internet.socket
Thanx Remy for your feedback
Much appreciated!

I'll try to use the Indy sockets now...

Best regards René


> {quote:title=Remy Lebeau (TeamB) wrote:}{quote}
> rene wrote:
> 
> > But indeed a disconnect event isn't fired eventhough there's a FIN sequence.
> 
> TTcpClient and TTcpServer are not event-driven components, even in non-blocking 
> mode.  The only time the TTcpClient.OnDisconnect event is fired is when TTcpClient.Close() 
> is called.  And in fact, in non-blocking mode, it would never fire OnDisconnect 
> anyway because it depends on the Connected property being true, and as I 
> mentioned earlier, Connected is never set to true in non-blocking mode.
> 
> > Is there a better solution in XE7
> 
> Use a different component.
> 
> > are the Indy components in XE2 any better?
> 
> MUCH MUCH better.  If you don't want to use Indy, and if you are only targetting 
> Windows, you could always install Embarcadero's dclSockets... package to 
> enable the older TClientSocket/TServerSocket components.  They are vastly 
> more usable than TTcpClient/TTcpServer.  But if you need cross-platform support, 
> Indy is your best choice, unless you decode to use another third-party cross-platform 
> library.
> 
> --
> Remy Lebeau (TeamB)

Vote for best answer.
Score: 0  # Vote:  0
Date Posted: 10-Sep-2014, at 2:42 AM EST
From: rene v.d. berge
 
Re: TTcpClient Connected property always indicates false  
News Group: embarcadero.public.cppbuilder.internet.socket
rene wrote:

> But indeed a disconnect event isn't fired eventhough there's a FIN sequence.

TTcpClient and TTcpServer are not event-driven components, even in non-blocking 
mode.  The only time the TTcpClient.OnDisconnect event is fired is when TTcpClient.Close() 
is called.  And in fact, in non-blocking mode, it would never fire OnDisconnect 
anyway because it depends on the Connected property being true, and as I 
mentioned earlier, Connected is never set to true in non-blocking mode.

> Is there a better solution in XE7

Use a different component.

> are the Indy components in XE2 any better?

MUCH MUCH better.  If you don't want to use Indy, and if you are only targetting 
Windows, you could always install Embarcadero's dclSockets... package to 
enable the older TClientSocket/TServerSocket components.  They are vastly 
more usable than TTcpClient/TTcpServer.  But if you need cross-platform support, 
Indy is your best choice, unless you decode to use another third-party cross-platform 
library.

--
Remy Lebeau (TeamB)

Vote for best answer.
Score: 0  # Vote:  0
Date Posted: 9-Sep-2014, at 9:16 AM EST
From: Remy Lebeau (TeamB)
 
Re: TTcpClient Connected property always indicates false  
News Group: embarcadero.public.cppbuilder.internet.socket
Thanx Remy,
When setting to bmBlocking the connected property is set. But because I only have one
thread running I prefer bmNonBlocking.

Thanx for you workaround, this way I'll have a way to indicate a valid socket when connecting. 
But indeed a disconnect event isn't fired eventhough there's a FIN sequence.

Is there a better solution in XE7 or are the Indy components in XE2 any better?

Best regards René


> {quote:title=Remy Lebeau (TeamB) wrote:}{quote}
> rene wrote:
> 
> > I'm using the TTcpClient class in C++Builder XE2.
> 
> I strongly recommend against using TTcpClient (or TTcpServer).  One, because 
> it is a horribly written component that is very difficult to use effectively. 
>  Two, because it is a dead component, deprecated and removed from the product 
> in XE6.
> 
> > As soon as I set the Active property to true, I can trace (via
> > wireshark) the TCP syn/syn ack sequence.
> > 
> > This tells me that there IS a TCP connection active. The connected
> > property however always indicates false.
> 
> Did you, by chance, set the BlockMode property to bmNonBlocking?  If so, 
> the Connected property will NEVER be set to true.
> 
> The ONLY time that Connected gets set to true is inside of TCustomIpClient::Open() 
> when the socket API connect() function returns success immediately.  In non-blocking 
> mode, that will never happen, as connect() always fails with a (WSA)EWOULDBLOCK 
> error instead.  TTcpClient DOES NOT take that into account, so it does not 
> know when a non-blocking connect() has finished its work or whether it succeeded/failed. 
>  You can, however, account for that manually in your own code:
> 
> {code}
> private:
>     int LastSocketError;
> 
> ...
> 
> if( TcpClient == NULL)
> {
>     TcpClient = new TTcpClient(NULL); // Now own TcpClient 
>     TcpClient->OnError = &TcpClientError;
> }
> 
> ...
> 
> void __fastcall CIpIo::TcpClientError(TObject *Sender, int SocketError)
> {
>     LastSocketError = SocketError;
> }
> 
> DWORD CIpIo::Open(int DeviceNumber, HDEVINFO DeviceList, const GUID* InterfaceGuid)
> {
>     if (!IPClient->Active)
>     {
>         LastSocketError = 0;
> 
>         IPClient->Active = true;
>         if (!IPClient->Active)
>         {
>             // error creating the socket
>             return ...;
>         }
> 
>         if (!IPClient->Connected)
>         {
>             if (LastSocketError != WSAEWOULDBLOCK)
>             {
>                 // error connecting to server
>                 IPClient->Active = false;
>                 return ...;
>             }
> 
>             // non-blocking connect, wait for result...
> 
>             bool Writable = false;
>             if (!IPClient->Select(NULL, &Writable, NULL, 5000))
>             {
>                 // not connected
>                 IPClient->Active = false;
>                 return ...;
>             }
>         }
> 
>         // connected to server
> 
>         Sleep(250); // Give TSEC server time to stack it's protocols....
>     }
> 
>     return 0;
> }
> {code}
> 
> --
> Remy Lebeau (TeamB)

Vote for best answer.
Score: 0  # Vote:  0
Date Posted: 9-Sep-2014, at 7:11 AM EST
From: rene v.d. berge
 
Re: TTcpClient Connected property always indicates false  
News Group: embarcadero.public.cppbuilder.internet.socket
rene wrote:

> I'm using the TTcpClient class in C++Builder XE2.

I strongly recommend against using TTcpClient (or TTcpServer).  One, because 
it is a horribly written component that is very difficult to use effectively. 
 Two, because it is a dead component, deprecated and removed from the product 
in XE6.

> As soon as I set the Active property to true, I can trace (via
> wireshark) the TCP syn/syn ack sequence.
> 
> This tells me that there IS a TCP connection active. The connected
> property however always indicates false.

Did you, by chance, set the BlockMode property to bmNonBlocking?  If so, 
the Connected property will NEVER be set to true.

The ONLY time that Connected gets set to true is inside of TCustomIpClient::Open() 
when the socket API connect() function returns success immediately.  In non-blocking 
mode, that will never happen, as connect() always fails with a (WSA)EWOULDBLOCK 
error instead.  TTcpClient DOES NOT take that into account, so it does not 
know when a non-blocking connect() has finished its work or whether it succeeded/failed. 
 You can, however, account for that manually in your own code:

{code}
private:
    int LastSocketError;

....

if( TcpClient == NULL)
{
    TcpClient = new TTcpClient(NULL); // Now own TcpClient 
    TcpClient->OnError = &TcpClientError;
}

....

void __fastcall CIpIo::TcpClientError(TObject *Sender, int SocketError)
{
    LastSocketError = SocketError;
}

DWORD CIpIo::Open(int DeviceNumber, HDEVINFO DeviceList, const GUID* InterfaceGuid)
{
    if (!IPClient->Active)
    {
        LastSocketError = 0;

        IPClient->Active = true;
        if (!IPClient->Active)
        {
            // error creating the socket
            return ...;
        }

        if (!IPClient->Connected)
        {
            if (LastSocketError != WSAEWOULDBLOCK)
            {
                // error connecting to server
                IPClient->Active = false;
                return ...;
            }

            // non-blocking connect, wait for result...

            bool Writable = false;
            if (!IPClient->Select(NULL, &Writable, NULL, 5000))
            {
                // not connected
                IPClient->Active = false;
                return ...;
            }
        }

        // connected to server

        Sleep(250); // Give TSEC server time to stack it's protocols....
    }

    return 0;
}
{code}

--
Remy Lebeau (TeamB)

Vote for best answer.
Score: 0  # Vote:  0
Date Posted: 8-Sep-2014, at 10:02 AM EST
From: Remy Lebeau (TeamB)