Board index » delphi » Indy: Waiting for Data of Arbitrary Length (2nd post)

Indy: Waiting for Data of Arbitrary Length (2nd post)

I'm still trying to find out the most efficient way with Indy of
processing incoming binary data of arbitrary lengh (i.e. the length of
the data packet is determined by information in the packet). This data
can come in at anytime (unsolicited) and other tasks need to be
performed while waiting.

For example, I am using a TIdTCPServer, and the OnExecute handler
looks like this:

procedure TForm4.IdTCPServerExecute(AThread: TIdPeerThread);
var
  B : byte;
begin
  with AThread.Connection do
    while Connected do
      begin
        ReadBuffer(B,1);
        //add byte to our own buffer
        //process this buffer if complete packet has been received
      end;
end;

As I understand this, AThread is thread running separately from the
main thread.

Questions:
How often is execute called? What thread does it run in?
Does the call to ReadBuffer put this thread to sleep until bytes are
received?
Is there a way to get all the bytes received in one call instead of
calling ReadBuffer for each byte? (The data format needs to stay as
is, so readstream is not a real option at this point.)

I would LOVE to see a demo or some sample code that does what I am
trying to do. Does anyone have any to share??

--Bruce

Bruce Vander Werf
bruc...@hotmail.com

 

Re:Indy: Waiting for Data of Arbitrary Length (2nd post)


I have the same situation, and could only come up with the same solution -
ReadBuffer one byte at  a time. I could see no other way and would also love
to hear of one.
John.

"Bruce Vander Werf" <bruc...@hotmail.com> wrote in message
news:3aacc95e.236273343@newsgroups.borland.com...

Quote
> I'm still trying to find out the most efficient way with Indy of
> processing incoming binary data of arbitrary lengh (i.e. the length of
> the data packet is determined by information in the packet). This data
> can come in at anytime (unsolicited) and other tasks need to be
> performed while waiting.

> For example, I am using a TIdTCPServer, and the OnExecute handler
> looks like this:

> procedure TForm4.IdTCPServerExecute(AThread: TIdPeerThread);
> var
>   B : byte;
> begin
>   with AThread.Connection do
>     while Connected do
>       begin
>         ReadBuffer(B,1);
>         //add byte to our own buffer
>         //process this buffer if complete packet has been received
>       end;
> end;

> As I understand this, AThread is thread running separately from the
> main thread.

> Questions:
> How often is execute called? What thread does it run in?
> Does the call to ReadBuffer put this thread to sleep until bytes are
> received?
> Is there a way to get all the bytes received in one call instead of
> calling ReadBuffer for each byte? (The data format needs to stay as
> is, so readstream is not a real option at this point.)

> I would LOVE to see a demo or some sample code that does what I am
> trying to do. Does anyone have any to share??

> --Bruce

> Bruce Vander Werf
> bruc...@hotmail.com

Re:Indy: Waiting for Data of Arbitrary Length (2nd post)


Quote
"John Dinning" <jdinn...@ozemail.com.au> wrote in message

news:98kmcv$i1b1@bornews.inprise.com...

Quote
> I have the same situation, and could only come up with the same solution -
> ReadBuffer one byte at  a time. I could see no other way and would also
love
> to hear of one.

I don't know the specifics of the protocol you're creating, buy I'd
recommend that it use some type of converstional style to know when things
are going to happen.  For instance, your client wants to send a JPG image
stream of arbitrary length to the server.  The conversation, after connect,
might look like:

    C: SEND
    S: READY or ERR
    C: Write Stream Length
    C: Write Stream Data
    S: OK or ERR Data Stream Size
    ...
    C: QUIT
    S: DONE

The client knowns that it initates all conversations, and must tell the
server what to expect. The server knowns that it must handle incoming
requests and generate both an ACK for the command and a response/result
message.

The client could write the stream length as a cardinal value for the server.

    try
        AClient.WriteLn('SEND');
        SResponse  := AClient.ReadLn;

        if SResponse <> 'OK' then
            raise EMyProtocolServerError.Create(SResponse);
            // or whatever you need to do to handle a server error

        AStream.Position := 0;
        AClient.WriteCardindal(AStream.Size);
        AClient.WriteStream(AStream);

        SResponse := AClient.ReadLn;

        if SResponse <> 'OK' then
            raise EMyProtocolDataError.Create(SResponse);
            // or whatever you need to do to handle
            // a data error or lost connection

    finally
        ...
    end;

The server could perform the converse in the OnExecute:

with AThread.Connection do
begin
    // say hello to the client

    while Connected do
    begin
         SCmd := ReadLn('', AServer.AcceptWait);

         if ReadLnTimedOut then
         begin
            // whatever you need to do to handle idle states
        end

        else if (SCmd = 'SEND') then
         begin
            WriteLn('READY');
            // or ERR if you can't receive
            iSize := ReadCardinal;
            ReadStream(AMemoryStream, iSize);

            if (AMemoryStream.Size <> iSize) then
                WriteLn('ERR Data stream size')
            else
            begin
                ProcessStream(AMemoryStream);
                WriteLn('OK');
            end;

         end

        else if SCmd = 'QUIT' then
        begin
            WriteLn('DONE');
            break;
        end;

    end;
    Disconnect;
end;

The command handling could be split up into individual methods, use numeric
response codes, etc.  But you get the idea.  This avoids trying to make the
blocking sockets behave like Async ones.

hth...

Don

Re:Indy: Waiting for Data of Arbitrary Length (2nd post)


Don,

Thanks for your response, but it's not what exactly what I am looking
for. The protocol is already in use, so I can't change it. The length
of the packet is stored in the first word of the packet, and the
packet can be of any length. Once a connections is established, the
client or server can initiate an message.
I desperately want to move to Indy with this project, but I have yet
to get a complete response on how to do this. I would really love to
see a demo that handles this type of traffic in the most efficient
way.

In your server example, does the OnExecute run in the main thread?

with AThread.Connection do
  while Connected do
    begin
      ...readln...
      if ReadlnTimeout then  
    end;

Does readln block the thread? Both my client and server have to be
able to do screen updates, respond to user input, etc. while talking
to each other.

--Bruce

Quote
On Tue, 13 Mar 2001 05:05:40 -0500, "Don" <dsid...@charter.net> wrote:

>"John Dinning" <jdinn...@ozemail.com.au> wrote in message
>news:98kmcv$i1b1@bornews.inprise.com...

>> I have the same situation, and could only come up with the same solution -
>> ReadBuffer one byte at  a time. I could see no other way and would also
>love
>> to hear of one.

>I don't know the specifics of the protocol you're creating, buy I'd
>recommend that it use some type of converstional style to know when things
>are going to happen.  For instance, your client wants to send a JPG image
>stream of arbitrary length to the server.  The conversation, after connect,
>might look like:

>    C: SEND
>    S: READY or ERR
>    C: Write Stream Length
>    C: Write Stream Data
>    S: OK or ERR Data Stream Size
>    ...
>    C: QUIT
>    S: DONE

>The client knowns that it initates all conversations, and must tell the
>server what to expect. The server knowns that it must handle incoming
>requests and generate both an ACK for the command and a response/result
>message.

>The client could write the stream length as a cardinal value for the server.

>    try
>        AClient.WriteLn('SEND');
>        SResponse  := AClient.ReadLn;

>        if SResponse <> 'OK' then
>            raise EMyProtocolServerError.Create(SResponse);
>            // or whatever you need to do to handle a server error

>        AStream.Position := 0;
>        AClient.WriteCardindal(AStream.Size);
>        AClient.WriteStream(AStream);

>        SResponse := AClient.ReadLn;

>        if SResponse <> 'OK' then
>            raise EMyProtocolDataError.Create(SResponse);
>            // or whatever you need to do to handle
>            // a data error or lost connection

>    finally
>        ...
>    end;

>The server could perform the converse in the OnExecute:

>with AThread.Connection do
>begin
>    // say hello to the client

>    while Connected do
>    begin
>         SCmd := ReadLn('', AServer.AcceptWait);

>         if ReadLnTimedOut then
>         begin
>            // whatever you need to do to handle idle states
>        end

>        else if (SCmd = 'SEND') then
>         begin
>            WriteLn('READY');
>            // or ERR if you can't receive
>            iSize := ReadCardinal;
>            ReadStream(AMemoryStream, iSize);

>            if (AMemoryStream.Size <> iSize) then
>                WriteLn('ERR Data stream size')
>            else
>            begin
>                ProcessStream(AMemoryStream);
>                WriteLn('OK');
>            end;

>         end

>        else if SCmd = 'QUIT' then
>        begin
>            WriteLn('DONE');
>            break;
>        end;

>    end;
>    Disconnect;
>end;

>The command handling could be split up into individual methods, use numeric
>response codes, etc.  But you get the idea.  This avoids trying to make the
>blocking sockets behave like Async ones.

>hth...

>Don

Bruce Vander Werf
bruc...@hotmail.com

Re:Indy: Waiting for Data of Arbitrary Length (2nd post)


bruc...@hotmail.com (Bruce Vander Werf) wrote in <3aacc95e.236273343
@newsgroups.borland.com>:

Quote
>As I understand this, AThread is thread running separately from the
>main thread.

Yes, it is in its own thread.

Quote
>How often is execute called? What thread does it run in?

It is called repeteadly as long as the socket is connected. It is called in
its own dedicated thread to handle that connection.

Have you read Intro To Indy?

Quote
>Does the call to ReadBuffer put this thread to sleep until bytes are
>received?

Essentially yes.

Quote
>Is there a way to get all the bytes received in one call instead of
>calling ReadBuffer for each byte? (The data format needs to stay as

Yes, pass a larger number to ReadBuffer. ReadBuffer will not return until all
the requested data has been read.

Quote
>is, so readstream is not a real option at this point.)

Why not? Thats what read stream does. It reads the first 32 bit number and
then reads that many bytes.

--
Chad Z. Hower (Kudzu) - Church Hill, TN - Team Indy
      "Programming is an art form that fights back"
Forget the Y2K problem, Lets fix the W2K problem.
http://www.pbe.com/Kudzu/ - Free Delphi/CBuilder components and articles

Re:Indy: Waiting for Data of Arbitrary Length (2nd post)


bruc...@hotmail.com (Bruce Vander Werf) wrote in
<3aae22e8.324731...@newsgroups.borland.com>:

Quote
>for. The protocol is already in use, so I can't change it. The length
>of the packet is stored in the first word of the packet, and the
>packet can be of any length. Once a connections is established, the
>client or server can initiate an message.

You're making this much harder than it is....
Really - forget how you think Indy works. Now approach it with a fresh mind.
Pretend you are reading from a file on disk. How would you approach that?

Quote
>Does readln block the thread? Both my client and server have to be

Yes. But it blocks ITS thread, not the MAIN thread.

For clients, you need to move it to a thread, or use a TIdAntiFreeze which
will "counteract" the freeze effect.

--
Chad Z. Hower (Kudzu) - Church Hill, TN - Team Indy
      "Programming is an art form that fights back"
Forget the Y2K problem, Lets fix the W2K problem.
http://www.pbe.com/Kudzu/ - Free Delphi/CBuilder components and articles

Re:Indy: Waiting for Data of Arbitrary Length (2nd post)


"Bruce Vander Werf" <bruc...@hotmail.com> schrieb im Newsbeitrag
news:3aae22e8.324731118@newsgroups.borland.com...
Quote
> Don,

.........
> In your server example, does the OnExecute run in the main thread?

> with AThread.Connection do
>   while Connected do
>     begin
>       ...readln...
>       if ReadlnTimeout then
>     end;

> Does readln block the thread? Both my client and server have to be
> able to do screen updates, respond to user input, etc. while talking
> to each other.

a server with its threads will never block your application,
each connection has its own "AThread". If you create your own
protocol, and work with readln, the thread will wait for a string.
I did not measure the cpu usage, but my V50 runs fife idtcpserver
and one udp server and i never have seen a delay.
The clients, you have to start readln in a thread, created by yourself.

Ernst Gerlach
ernst.gerl...@epost.de
http://www.gerlach-mtl.de
--- use plain text only in email ---

Re:Indy: Waiting for Data of Arbitrary Length (2nd post)


Sorry Ernst,
we are talking about different applications:
There exists an other world beside chatting and file transfer.

There are some devices out in our world (or at least in mine)
which use TCP for remote control and data collection.
The most important property of such a communication application
is to recover from any transmission error gracefully and safety with
a small and controllable time delay.

If you would have had a look on any industrial serial protocoll
(e.g. 3964/R), you would have recogniced that the most
used function is a readdata with specified buffer size and
timeout.

If you thrust blindly in the transmitted data size, you have no
chance to recover. It might be an unlikely case, but consider the
data size do be accidently FF FF FF FF. This would block the
control channel for a very long time  - logical.

As I stated to Hadi some time ago:
Indy will stay on the level of a chatting engine as long as it does
not support blockread with timeout. Have a look: this function is
already realized for ASCII - 'readln', used for chatting.

Ernst, it might be that I have some problems with logic thinking.
But if you have some advice how to handle my problem(s), please
let me (us) know.

Looking forward to hear from you

Hans Hochreiter
jhochrei...@arri.at

Ernst Gerlach <ernst.gerl...@epost.de> schrieb in im Newsbeitrag:
3ab2148c_2@dnews...

Quote
> Sorry, if i read "Waiting for Data of Arbitrary Length",
> i feel, that some people have problems with logig thinking.
> If some program wants to send data, the program knows
> the count of data. Therefore its no problem, that the sending
> program will send the count at first and than the data as a
> stream. This is a built in function in Indy, and this will produce
> a defined protocol handling.
> The only problem, i know, where to wait for "Arbitrary Length",
> is, if some one wants to built a packet sniffer.

> Ernst Gerlach
> ernst.gerl...@epost.de
> http://www.gerlach-mtl.de
> --- use plain text only in email ---

Re:Indy: Waiting for Data of Arbitrary Length (2nd post)


"Hans Hochreiter" <jhochrei...@arri.at> schrieb im Newsbeitrag
news:3ab5fa5a_1@dnews...

Quote
> Sorry Ernst,
> we are talking about different applications:
> There exists an other world beside chatting and file transfer.

> .......

> If you would have had a look on any industrial serial protocoll
> (e.g. 3964/R), you would have recogniced that the most
> used function is a readdata with specified buffer size and
> timeout.

Sorry, but i am just handling the 3964 protocol (over serial connection)
in this case, you can use the "dle" as a delimmiter an process
the last byte of the string. If last byte is a DLE too, start to continue
receiving, else ......

As i see a "at" in your adress, you could send me a mail, we could
continue the dialog in german, my english is very, very bad

regards / Mit freudlichen Gr?en

Ernst Gerlach
E.Gerlach-Automation, Goethestr.73, D-63477 Maintal
Tel.: +49/0-6109-762557 Fax: -762558
ernst.gerl...@epost.de
http://www.gerlach-mtl.de/

Other Threads