🚀 go-pugleaf

RetroBBS NetNews Server

Inspired by RockSolid Light RIP Retro Guy

Thread View: borland.public.cppbuilder.internet.socket
7 messages
7 total messages Started by Roberto Zais Thu, 21 Jul 2005 21:25
a IdTCPClient solution
#3694
Author: Roberto Zais
Date: Thu, 21 Jul 2005 21:25
157 lines
6315 bytes
This is a client application using IdTCPClient . This application receives a
flow composed of big messages : 10Kbytes each.
I have used some code that was shown in  this  newsgroup . BUT that was a
server application .
Please , can someone say me if the application-use that I did is correct ?
It seems working ok .
[Rarely I notice  errors, They are rare but persistent ..( Connection
refused) It seems to depend of the environment or other problems (?). .]
At the bottom of the mail I report the original suggestions I have read in
this newsgroup (but, for server application)

Perhaps the solution is not the best one as speed or performace : shall I
use streams ?  How?
Are there limits to the size of data and the time related throughput ? (
beyond  the obvious limits of the network...)

Which is the more simple performant and recommendable approach ?
I had a look  at  " please help me..socket file transfer" thread , but I
feel a little confused .
More, I must use Indy client ( I have Indy9 installed OK)
Thank you all for any help or opinion
Roberto

the setup includes

TCPClient->Host = iaddress;
TCPClient->Port = iport;  //  8023
TCPClient->Connect(0);  //  Timeout - millisecondi
----------------------------------------------------------------------------
----------

This  is called cyclically

ContactThread->socket_read_procedure();

----------------------------------------------------------------------------
----------

void __fastcall TContactThread::socket_read_procedure(void)
{
AnsiString Buffer;
int a,Count,size, size_readable;
int bufsize;

TCPClient->ReadTimeout = 100;            //READ_STACK_TIMEOUT;

//  $$$ variante newsgroup
try     {
        if(TCPClient->InputBuffer->Size  == 0 )
                size_readable =
TCPClient->ReadFromStack(true,IdTimeoutDefault,true);
              else
                size_readable = TCPClient->InputBuffer->Size;
        }

       catch(Exception& e){       // Without display
          String sbuf = String(e.ClassName()) + " " + e.Message.c_str();
          MessageText = sbuf;
                                            // possible error :
EIdReadTimeout    .   Other errors ??
          if (String(e.ClassName()) == "EIdReadTimeout")
                  return;                 // lets in waiting read loop
          }
if(!size_readable)
        return;

    if(ser_start <= ser_end)
                                            // circular buffer
         size = Min((ser_end + MAX_BUF - ser_start),size_readable);
            else
                                            // buffer disposto linearmente :
                                            // spazio libero = semplice
differenza puntatori
         size = Min((ser_end - ser_start),size_readable);    // al limite,
zero

                                                         // si adotta size
in modo da leggere dati solo per lo spazio disponibile
    char *buf = new char[size];
    TCPClient->ReadBuffer(buf, size);     // are possible any errors in this
phase  ???

    serial_lock=true;
    for(a=0; a<size; a++)
        {
        mychar[ser_end]= buf[a];     // posizione attuale : posizione libera
di inserz.
        ser_end++;
        char_ready++;
        if(ser_end>(MAX_BUF-1))      // eventuale rotazione circolare buffer
           ser_end=0;
        }
    serial_lock=false;
    delete[] buf;
    return;


----------------------------------------------------------------------------
---------------------------------------------
Server solution provided  14/2/2005

"Jonathan Benedicto" <incorrect@no.server> wrote in message
news:42110245$1@newsgroups.borland.com...

> Eg. If I read data like this :

You should not be looping like that.  The OnExecute event is already looped
by TIdTCPServer.  Your code should only be processing a single iteration of
that internal loop, not running your own loop at all:

    void __fastcall TForm1::IdTCPServer1Connect(TIdPeerThread *AThread)
    {
        AThread->Connection->ReadTimeout = 1000;
    }

    void __fastcall TForm1::IdTCPServer1Execute(TIdPeerThread *AThread)
    {
        char buffer[200];

        if( AThread->Connection->InputBuffer->Size == 0 )
        {
            int read = AThread->Connection->ReadFromStack(true,
IdTimeoutDefault, false);
            if( read == -1 ) // timeout
                return;
        }

        do
        {
            int bufsize = min(AThread->Connection->InputBuffer->Size, 200);
            AThread->Connection->ReadBuffer(buffer, bufsize);
            // use buffer as needed...
        }
        while( bufsize > 0 );
    }

> Then the app can only work with 200 bytes chucks of data. Even if the
> sending app sent a 100 byte chunk and then a 300 byte chunk.

I would strongly recommend that you prefix your packets with the actual size
of the packets.  Then you don't have to limit your buffer size during
reading, and can send small and large packets alike:

    void __fastcall TForm1::IdTCPServer1Execute(TIdPeerThread *AThread)
    {
        int size = AThread->Connection->ReadInteger(true);
        if( size > 0 )
        {
            char *buffer = new char[size];
            AThread->Connection->ReadBuffer(buffer, size);
            // use buffer as needed...
            delete[] buffer;
        }
    }


Gambit
Re: a IdTCPClient solution
#3698
Author: Remy Lebeau (TeamB)
Date: Thu, 21 Jul 2005 22:23
85 lines
4045 bytes
"Roberto Zais" <rzaiss@tiscali.it> wrote in message
news:42e010be$1@newsgroups.borland.com...

> [Rarely I notice  errors, They are rare but persistent ..( Connection
> refused)

"Connection refused" means that either 1) the server is not running, or 2)
it has too many pending client requeusts and can't accept anymore until it
handles the ones that are already pending.

> TCPClient->ReadTimeout = 100;            //READ_STACK_TIMEOUT;

Why are you setting that every time the function is called?  You don't need
to.  Just set it once before calling Connect().  Or better yet, don't set it
at all.  Pass your timeout to ReadFromStack() directly instead of
IdTimeoutDefault.

>         if(TCPClient->InputBuffer->Size  == 0 )
>                 size_readable =
> TCPClient->ReadFromStack(true,IdTimeoutDefault,true);
>               else
>                 size_readable = TCPClient->InputBuffer->Size;
>         }

>        catch(Exception& e){       // Without display

Always catch exception by 'const' references:

    catch(const Exception& e){       // Without display

>           String sbuf = String(e.ClassName()) + " " + e.Message.c_str();

Don't use c_str() like that:

    String sbuf = String(e.ClassName()) + " " + e.Message;

>           if (String(e.ClassName()) == "EIdReadTimeout")
>                   return;                 // lets in waiting read loop

That is not a good way to handle exception testing.  If you want to know if
an exception is a particular class type, then you should be using
dynamic_cast instead:

    if (dynamic_cast<EIdReadTimeout*>(&e) != NULL )

Better would be to catch the specific exception type directly instead:

    catch(const EIdReadTimeout &)
    {
        return;
    }

Better would be to not throw an exception at all.  Specify False instead of
True for the ARaiseExceptionOnTimeout parameter of ReadFromStack().  That is
what the earlier code sample was doing.

>     if(ser_start <= ser_end)
>                                             // circular buffer
>          size = Min((ser_end + MAX_BUF - ser_start),size_readable);
>             else
>                                             // buffer disposto linearmente
:
>                                             // spazio libero = semplice
> differenza puntatori
>          size = Min((ser_end - ser_start),size_readable);    // al limite,
> zero

How EXACTLY are your packets actually formatted?  It doesn't look like you
are taking the advice of the earlier code sample:

    "I would strongly recommend that you prefix your packets with the actual
size of the packets.  Then you don't have to limit your buffer size during
reading, and can send small and large packets alike"

>     TCPClient->ReadBuffer(buf, size);
> // are possible any errors in this phase  ???

No, if the InputBuffer actually has the specified number of bytes available.
If it doesn't, then it has to call ReadFromStack() again (as well as
CheckForDisconnect()) to read more bytes, and that can potentially throw
exceptions.


Gambit
Re: a IdTCPClient solution
#3700
Author: Roberto Zais
Date: Fri, 22 Jul 2005 10:17
67 lines
3267 bytes
First of all , please,  I have a question :  is  TCPClient->Disconnect();
innocuous  even if already disconnected , too ??
I didn' t find this information in the help.

> Better would be to not throw an exception at all.  Specify False instead
of
> True for the ARaiseExceptionOnTimeout parameter of ReadFromStack().  That
is
> what the earlier code sample was doing.

so, I have modified the code in this way :

try     {
        if(TCPClient->InputBuffer->Size  == 0 )
                size_readable = TCPClient->ReadFromStack(true,100,false);
              else
                size_readable = TCPClient->InputBuffer->Size;
        }
       catch(const Exception& e){
          String sbuf = String(e.ClassName()) + " " + e.Message;
          MessageText = sbuf;    //  for only eventually debug info
          return;                         // all exception in this phase :
return (wait loop)
                                            //  ( there is a global timeout
on the RX operation)

          }
if(!size_readable)
        return;

else:  ......  acquisition of data

Now, I don' t experiment(by debugging) any return by exception: which other
exception are possible , except rxtimeout?
I remember at the beginning, I set the try-catch because it seemed that in
presence of a bad condition ( typically
read timeout)  the size returned  by TCPClient->ReadFromStack was bad and I
got blockings and bad
results .
What does it happen if I remove the try-catch and set
TCPClient->ReadFromStack(true,100,false);  ?
Is size_readable really  reliable ?


>
> How EXACTLY are your packets actually formatted?  It doesn't look like you
> are taking the advice of the earlier code sample:
>
>     "I would strongly recommend that you prefix your packets with the
actual
> size of the packets.  Then you don't have to limit your buffer size during
> reading, and can send small and large packets alike"
>

Yes, the only reason is that I fear disalignment . But ,really ,there is not
a difference concerning disalignment .
My packets begin with 0x16 and end with 0x4  all other is ASCII char.
When the first byte is lost is lost and the re align procedure is the same .
More, through a TCP conn.
nothing should be lost.

On the whole, is this solution  the more common and fast?
Using streams may be better or not ?

Thanks, very much , for your help

Roberto
Re: a IdTCPClient solution
#3701
Author: Remy Lebeau (TeamB)
Date: Fri, 22 Jul 2005 17:14
89 lines
3824 bytes
"Roberto Zais" <rzaiss@tiscali.it> wrote in message
news:42e0c5b2@newsgroups.borland.com...
> First of all , please,  I have a question :  is  TCPClient->Disconnect();
> innocuous  even if already disconnected , too ??
> I didn' t find this information in the help.

> so, I have modified the code in this way :

You did not pay attention to what the earlier code was doing.  Remove the
try..catch, and size_readable will be -1 on timeout so (!size_readable) will
not work.  Use (size_readable < 1) instead.

> I remember at the beginning, I set the try-catch because it seemed
> that in presence of a bad condition ( typically read timeout)  the size
> returned  by TCPClient->ReadFromStack was bad and I got blockings
> and bad results .

That is because you are not checking the size properly.

> Is size_readable really  reliable ?

Yes.  It returns how many bytes the socket actuall returned and Indy then
buffered for later reading.

> Yes, the only reason is that I fear disalignment . But ,really ,there
> is not a difference concerning disalignment .

What are you talking about?

> My packets begin with 0x16 and end with 0x4

That is fine, though including the packet size insode each packet as well
would be better.

With that said, since your packets are already framed, I would suggest not
calling ReadBuffer() until you have first validated that all of the packet
data is actually available.  For example (untested):

    TCPClient->Host = iaddress;
    TCPClient->Port = iport;
    TCPClient->ReadTimeout = 100;
    TCPClient->Connect(0);

    void __fastcall TContactThread::socket_read_procedure(void)
    {
        int size_readable = TCPClient->ReadFromStack(true, IdTimeoutDefault,
false);
        if( size_readable == -1 )
            return;

        do
        {
            char *ptr = (char*) TCPClient->InputBuffer->Memory();

            int start = MemoryPos("\x16", ptr,
TCPClient->InputBuffer->Size);
            if( start < 1 )
            {
                TCPClient->InputBuffer->Clear();
                break;
            }

            int end = MemoryPos("\x4", ptr+start,
TCPClient->InputBuffer->Size - start);
            if( end < 1 )
                break;

            if( start > 1 )
                TCPClient->InputBuffer->Remove(start-1);

            int size = ((end-start)+1);
            char *buf = new char[size];

            TCPClient->ReadBuffer(buf, size);

            // use buffer as needed...
            delete[] buf;
        }
        while( TCPClient->Connected() );
    }

> When the first byte is lost

TCP/IP guarantees data integrity.  If data is corrupted, then something is
wrong with the socket in general and it should be reporting errors anyway.


Gambit
Re: a IdTCPClient solution
#3702
Author: Roberto Zais
Date: Fri, 22 Jul 2005 21:40
10 lines
1386 bytes
Great!  many thanks, Remy .

> > First of all , please,  I have a question :  is
TCPClient->Disconnect();
> > innocuous  even if already disconnected , too ??
Have you please an answer about this?   Actually there is the  risk I close
more times
the connection . Is it allowed ?
thanks
Roberto
Re: a IdTCPClient solution
#3703
Author: Remy Lebeau (TeamB)
Date: Fri, 22 Jul 2005 22:34
15 lines
1494 bytes
"Roberto Zais" <rzaiss@tiscali.it> wrote in message
news:42e165a4@newsgroups.borland.com...

> Have you please an answer about this?   Actually there
> is the risk I close more times the connection . Is it allowed ?

You could have just looked at Indy's source code for that answer.

Yes, you can call Disconnect() multiple times.  If you have multiple threads
involved, though, then I suggest you protect access to the connection so
that threads do not access it at the same time.


Gambit
Re: a IdTCPClient solution
#3706
Author: Roberto Zais
Date: Sat, 23 Jul 2005 11:06
24 lines
1791 bytes
Thank you very much for your answer, Remy

Roberto

"Remy Lebeau (TeamB)" <no.spam@no.spam.com> ha scritto nel messaggio
news:42e1750b$1@newsgroups.borland.com...
>
> "Roberto Zais" <rzaiss@tiscali.it> wrote in message
> news:42e165a4@newsgroups.borland.com...
>
> > Have you please an answer about this?   Actually there
> > is the risk I close more times the connection . Is it allowed ?
>
> You could have just looked at Indy's source code for that answer.
>
> Yes, you can call Disconnect() multiple times.  If you have multiple
threads
> involved, though, then I suggest you protect access to the connection so
> that threads do not access it at the same time.
>
>
> Gambit
>
>
Thread Navigation

This is a paginated view of messages in the thread with full content displayed inline.

Messages are displayed in chronological order, with the original post highlighted in green.

Use pagination controls to navigate through all messages in large threads.

Back to All Threads