Newsgroups : Borland : borland.public.delphi.internet.winsock : 2007 Sep : Re: Converting From TClientSocket

www.cryer.info
Managed Newsgroup Archive

Re: Converting From TClientSocket

Subject:Re: Converting From TClientSocket
Posted by:"Remy Lebeau (TeamB)" (no.spam@no.spam.com)
Date:Mon, 3 Sep 2007 22:40:35

"Jack Mason" <jackmason@mindspring.com> wrote in message
news:46dcd38b$1@newsgroups.borland.com...

> You were right on the byte count, it was the total bytes
> following the response header.

I would have expected as much.  Most protocols work that way.  It is not
common to include the header size in the byte count that the header reports.
It doesn't make much sense to do that, unless the header itself is
variable-length.

> As proposed, the read error still occurs.

As I mentioned to you earlier, you would get a timeout error (assuming you
changed the ReadTimeout property from its default value) if you try to read
too many bytes from the connection.  Given the new info you have provided,
that is clearly the case afterall - you are telling Indy to read 1 too many
bytes.  Keep reading to find out why.

> If I insert a delay of at least 2 seconds before the first
> readstring, the readstring works and gets the first character
> of the following data (which it is supposed to do).

No, it is not supposed to.  You said earlier that the header is 34 bytes, so
the first ReadString() is reading 34 bytes.  If the header really were 34
bytes, then the first call to ReadString() would never be including any
characters from the trailing data.  That would only happen if the header was
not actually 34 bytes in size to begin with, which is actually the case -
the header is 33 bytes, not 34 bytes.

> However, the second read, while appearing to be successful,
> returns with a length of zero (but no error).

That can only happen if the requested byte count is 0.  It is not possible
for ReadString() to return an empty string otherwise.  It would raise an
exception instead.

> The documentation seems to say the read will delay until the
> data arrives and that a readstring will return 'n' bytes from an
> internal buffer with additional 'x' bytes on the next readstring
> if there is data present.

Which documentation are you referring to?  Indy's?  That is not what
ReadString() does.

> The blocking action of the socket is fine, but it appears it
> may need to be in a thread to work properly?

No, a thread is not needed for that.

> Here is the actual info if it is any help to you.

That info does not match what you said earlier.  You said that the response
header was 34 bytes.  Now you are saying that it is 33 bytes instead.  That
makes a big difference.  The first call to ReadString() needs to be reading
33 bytes, not 34.  Otherwise the second ReadString() will try to read 1 too
many bytes and block until the timeout elapses because it is waiting for
data that will never arrive.

Look at the earlier code again and see for yourself why that is happening:

    Received "112345677654321PASSWORDISTK2000139780618610037"

    Response := Socket.ReadString(34);
    Result is "112345677654321PASSWORDISTK2000139"

    Byte_Count := StrToInt(Copy(Response, 29, 5));
    Result is 13

    Response := Socket.ReadString(Byte_Count); // Byte_Count=13
    data available is "780618610037" - only 12 bytes long
    timeout error - there is no 13th byte available!!!

Now look at what happens when you tell the first ReadString() to read 33
bytes instead of 34:

    Received "112345677654321PASSWORDISTK2000139780618610037"

    Response := Socket.ReadString(33);
    Result is "112345677654321PASSWORDISTK200013"

    Byte_Count := StrToInt(Copy(Response, 29, 5));
    Result is still 13

    Response := Socket.ReadString(Byte_Count); // Byte_Count=13
    data available is "9780618610037".
    No error!!!!!

So you did not follow your original spec correctly, and you got an error
because of it.

Now, with that said, the code I gave you earlier could be taken a step
further to better match the spec you are working from:

    procedure TForm1.Start;
    var
        Byte_Count: Integer;
    begin
        Socket.Host := Host;
        Socket.Port := Port;
        Socket.Connect(5000);
        try
            Socket.Write(Request_Data);
            Socket.ReadString(28); // ignore copy of Request data
            Byte_Count := StrToInt(Socket.ReadString(5)); // read byte count
            Response := Socket.ReadString(Byte_Count);
        finally
            Socket.Disconnect;
        end;
    end;


Gambit

Replies:

In response to:

www.cryer.info
Managed Newsgroup Archive