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
Author: Roberto Zais
Date: Thu, 21 Jul 2005 21:25
Date: Thu, 21 Jul 2005 21:25
157 lines
6315 bytes
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
Author: Remy Lebeau (TeamB)
Date: Thu, 21 Jul 2005 22:23
Date: Thu, 21 Jul 2005 22:23
85 lines
4045 bytes
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
Author: Roberto Zais
Date: Fri, 22 Jul 2005 10:17
Date: Fri, 22 Jul 2005 10:17
67 lines
3267 bytes
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
Author: Remy Lebeau (TeamB)
Date: Fri, 22 Jul 2005 17:14
Date: Fri, 22 Jul 2005 17:14
89 lines
3824 bytes
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
Author: Roberto Zais
Date: Fri, 22 Jul 2005 21:40
Date: Fri, 22 Jul 2005 21:40
10 lines
1386 bytes
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
Author: Remy Lebeau (TeamB)
Date: Fri, 22 Jul 2005 22:34
Date: Fri, 22 Jul 2005 22:34
15 lines
1494 bytes
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
Author: Roberto Zais
Date: Sat, 23 Jul 2005 11:06
Date: Sat, 23 Jul 2005 11:06
24 lines
1791 bytes
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