• Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 5256
  • Last Modified:

How to use Readbuffer on Indy's TIdTCPClient component?

Hi!

void* VMes = (void*) malloc(10000);
....
TIdTCPClient* TCPConn = new TIdTCPClient(this);
...
.....
..
TCPConn->ReadBuffer(VMes,10000);

My problem is that size of the message that I recev from the server will change from message to message.
So I would like to use a size that is larger then the largest message but i cant get it to work.
When i use it this way it is stopped at TCPConn->ReadBuffer(VMes,10000) it is't a error or a exception.

The app works fine if i use static size like this

void* VMes = (void*) malloc(sizeof(*mes));
....
TIdTCPClient* TCPConn = new TIdTCPClient(this);
...
.....
..
TCPConn->ReadBuffer(VMes,sizeof(*mes));

where mes is a pointer to a structure that I am using later in the program.
Dose any one know how the readbuffer works?
The size of the mes is exactly the size that my app recv at this momemt but I have to make it flexible so that it can recv diffrent packages with diffrent sizes.
0
mikrodidakt
Asked:
mikrodidakt
  • 6
  • 5
  • 4
2 Solutions
 
kode99Commented:
The problem is that ReadBuffer will continue to try to read until it has reached the size you specify.  So it will wait until a timeout, if any, for more data.

You can do one of two things, send the size of the message at the start of the message or use a end of line indication.

So for example you could use ReadLn which will keep reading untill it hits the specified terminator,  possibly a linefeed or carriage return.

The other approach would be to do a ReadInteger first to get the size of the incoming data and then call the ReadBuffer with the size.

0
 
George TokasCommented:
If you didn't create the component at runtime but just dropped the component at your form how you will read the buffer then??
There is a point to this question because I don't use Indy myself even though I'm registered to their comercial products.

George Tokas.
0
 
kode99Commented:
Not sure I understand you question George,  you handle the TIdTCPClient the same way whether it is design time created or runtime.  Well except for having to code the settings instead of entering them into the properties.

The component maintains its own internal buffer,  the ReadBuffer only transfers the data from the components internal buffer to the buffer you pass with the ReadBuffer command.

0
Keep up with what's happening at Experts Exchange!

Sign up to receive Decoded, a new monthly digest with product updates, feature release info, continuing education opportunities, and more.

 
mikrodidaktAuthor Commented:
The problem is that i have no control of the Server and the protocol.
Some idiots parden my french have writen a server that is implemented on a device and the protocol is that when a connection is established the server starts to send data. A message dose have a start tag but no end tag and the size of the message is in the middle of the message. Imight be able to use the timeout in some way because the server is sending a message in every 1-3 sec. So could i set the timeout to 1 sec?
0
 
mikrodidaktAuthor Commented:
So maybe i could set the timeout for less then 1 sec?
0
 
mikrodidaktAuthor Commented:
I would like to use TIdManagedBuffer dose any one know how to create it? I tryed following.

TIdManagedBuffer* bufferManager = new TIdManagedBuffer(this);

but apperently there should be alot more parameters and i cant find what kind of parameters.
0
 
mikrodidaktAuthor Commented:
Forget the question above.
I can get TIdManagedBuffer trough TIdTCPConnection but how do i get the TIdTCPConnection?    
0
 
mikrodidaktAuthor Commented:
Forget the entire question
0
 
George TokasCommented:
>>Not sure I understand you question George,  you handle the TIdTCPClient the same way whether it is design time created or runtime.

When created at design time we have allready the handler to write when a message arrive...
On the other hand on runtime creation usually we have to assign the handler after we create the component with new keyword as default handler or as overriden.
That was the meaning of my question.
As I wrote I don't use Indy myself...
But for typical TClient/TServer cases, server side, I'm using a class to deal with each client connection by assigning a TCustomWinSocket to the class and override the OnEvent method inside the class itself after the socket is assigned to the instance (Client connect).

George Tokas.
0
 
George TokasCommented:
>>The problem is that i have no control of the Server and the protocol.
Some idiots parden my french have writen a server that is implemented on a device and the protocol is that when a connection is established the server starts to send data. A message dose have a start tag but no end tag and the size of the message is in the middle of the message. Imight be able to use the timeout in some way because the server is sending a message in every 1-3 sec. So could i set the timeout to 1 sec?


Why don't you use the classic TClientSocket.
At OnRead you can read the entire buffer and there will be all the data the server sended (StartTag + data). If there is a time out before sending the next packet then there are all the data sended at that time from the server.

George Tokas.
0
 
kode99Commented:
Too bad,  I thought maybe you had control over the server side of things also.  Would the ConnectAndGetAll work?  Does the client connect and the server just dump data and then close the connection?  If so that is easy to manage.

Another alternative could be to read the data in small chunks to look for the size message,  if there is some kind of indicator with the size you might be able to use the WaitFor command.  So your code would connect then wait for the marker with the size and then read remainder of the buffer based on that.  Also you could watch for the start marker if there are multiple items coming through the same connection.

I'm guessing you spotted the TIdConnection etc.  When working with the Indy stuff in CBuilder I find it very useful to use the hpp files as references to the classes.   The help is decent but it is missing things and some stuff is not that clear.

George,  there is no need to use handlers with TIdTCPClient.  Just do the code inline.  So you connect,  make the request, read responses etc without using any event handlers.  Because of the blocking it will proceed in order and the program will wait when needed.  That's why it works so well in a thread. TIdTCPClient is only to be used for the client side,  the TIdTCPServer is another matter.
0
 
George TokasCommented:
@kode99
At the next issue of bcbjournal , http://www.bcbjournal.com/index.php ,(after June's issue) there will be an article about networking Client/Server based using TClientSocket and TServerSocket.
Server side is using an instance of a class handling everything in communication by itself.
It is using the strategy I posted before.
I had bad time trying to use Indy and imagine that I'm registered to the commercial products... Maybe because I don't use Delphi... Or maybe because I'm idiot... Who knows?
Anyway I made it with standard TClient/TServer sockets without any errors and that is the reason for all my proposals here...

George Tokas.
0
 
kode99Commented:
Indy's strength is the ready to go components that it has,  but it can also be a weakness.  I can put together a very functional client/server with full encryption real fast  BUT if you need to bend things to do something special it can get messy.

Largely I think that us CBuilder guys get the short end of the stick with many component's.  I have learned  Delphi over the years out of necessity and it does come in handy.  I do not think Indy has got any CBuilder examples newer than version 8,  and they are on 10 now - though I think that 10 does not fully support CBuilder yet.

I have also used the ICS package which works quite well,  nice FTP server component that works really well.
http://www.overbyte.be/frame_index.html

I look forward to the article.
0
 
mikrodidaktAuthor Commented:
Thanks for the help.
I decided to use
>>Another alternative could be to read the data in small chunks to look for the size message

the solution became following if someone should be intereseted in the future.

TCPConn->ReadBuffer(HeaderBuffer,sizeof(Header));
header = static_cast<Header*>(HeaderBuffer);
BodyBuffer  = malloc(header->MBL);
//Checking the header for errors
..
...
.....
TCPConn->ReadBuffer(BodyBuffer,header->MBL);
body  =  static_cast<S_record*>(BodyBuffer);

Some things to notice when createing the IdTCPClinet in run-time is to "#include <winsock2.h>" before windows.h. View the link.

http://carcino.gen.nz/tech/win/include_winsock2_header_file_first.php 
0
 
George TokasCommented:
>>Some things to notice when createing the IdTCPClinet in run-time is to "#include <winsock2.h>" before windows.h.

The same apply on many 3rd party components...
A re-arrange of the headers usually do the work...

George Tokas.
0
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

Join & Write a Comment

Featured Post

Free Tool: Path Explorer

An intuitive utility to help find the CSS path to UI elements on a webpage. These paths are used frequently in a variety of front-end development and QA automation tasks.

One of a set of tools we're offering as a way of saying thank you for being a part of the community.

  • 6
  • 5
  • 4
Tackle projects and never again get stuck behind a technical roadblock.
Join Now