BorlandTalk.com Forum Index BorlandTalk.com
Borland discussion newsgroups
 
Archives   FAQFAQ   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

Strange behavior sending stream from IdTCPClient to IdTCPSer

 
Post new topic   Reply to topic    BorlandTalk.com Forum Index -> Delphi Internet Winsock
View previous topic :: View next topic  
Author Message
Staffan
Guest





PostPosted: Fri Apr 23, 2004 6:25 am    Post subject: Strange behavior sending stream from IdTCPClient to IdTCPSer Reply with quote



Hi all

Can anyone explain to me why the stream size has grown 1 byte when sending
from
client to server. This don't seem to occur when sending the other way.

My code:
Client-side:
FMyBuf.SaveToStream(memStream);
memSize := memStream.Size; // ---------------Checked to be 287 bytes

IdTCPClient1.Connect(500);
IdTCPClient1.WriteStream(memStream, true, true);
// According to the documentation this means, position to the stream origin
prior to sending stream data,
// make a WriteInteger to send the stream size to the peer connection.
IdTCPClient1.Disconnect;


Server-side:
i := ReadInteger; // reading stream size gives size = 167772161
ReadStream(memStream, i, false); // checking memStream size gives 288 bytes

Documentation for WriteInteger indicates:
Convert the Host byte-order to Network byte-order. Default value is True.

and for ReadInteger:
Indicates that the result should be converted from Internet to Intel
byte-order. Default value is True.

To my understanding this would mean that the stream size is at the
client-side first converted to network byte-order and
converted back again on the server side.

Thanks in advance.
Staffan


Back to top
Remy Lebeau (TeamB)
Guest





PostPosted: Fri Apr 23, 2004 6:27 am    Post subject: Re: Strange behavior sending stream from IdTCPClient to IdTC Reply with quote




"Staffan" <Staffan.Bergbom (AT) lm (DOT) se> wrote


Quote:
i := ReadInteger; // reading stream size gives size = 167772161

It should have returned 287, not 167772161.

Why are you calling ReadInteger() manually anyway? If you leave the
AByteCount parameter of ReadStream() set to -1, ReadStream() will call
ReadInteger() internally for you.

----- client -----

FMyBuf.SaveToStream(memStream);
IdTCPClient1.Connect(500);
try
IdTCPClient1.WriteStream(memStream, True, True);
finally
IdTCPClient1.Disconnect;
end;


----- server -----

ReadStream(memStream, -1, False);


Gambit



Back to top
Staffan
Guest





PostPosted: Fri Apr 23, 2004 12:54 pm    Post subject: Re: Strange behavior sending stream from IdTCPClient to IdTC Reply with quote



Playing around using your advice I found out the following.

A more complete code-snippet of the server code looks like this:

with AThread.Connection do
begin
try
memStream := TMemoryStream.Create;

try
// READ FIRST WHAT KIND OF INDATA THAT IS COMING
// request := Readln; // -------------ACTIVATING
THIS GIVES RIGHT MEMSTREAM SIZE
request := Readln(#13, 10000); // ------------ ACTIVATING THIS GIVES
WRONG MEMSTREAM SIZE
if not ReadLnTimedOut then
begin
if Pos('Integer', request) <> 0 then // INTEGER INPUT
i := ReadInteger
else if Pos('String', request) <> 0 then // STRING INPUT
temp := Readln
else if Pos('MemStream', request) <> 0 then // MEMSTREAM INPUT
begin
ReadStream(memStream, -1, false);
end
else
Writeln('Error!!!');
end
else
Writeln('TIMEOUT!!!');

except
on E: Exception do
ShowMessage(Format('Exception %s Occured: %s', [E.ClassName,
E.Message]));
end;
finally
i := memStream.Size;
Panel1.Caption := 'memStream.Size:' + IntToStr(memStream.Size);
if Connected then
DisconnectSocket;
FreeAndNil(memStream);
end;
end;

Can you explain why ReadLn works, but not ReadLn(#13, 10000) ?

Regards
Staffan

"Remy Lebeau (TeamB)" <gambit47.no.spam (AT) no (DOT) spam.yahoo.com> skrev i
meddelandet news:4088b8d3$1 (AT) newsgroups (DOT) borland.com...
Quote:

"Staffan" <Staffan.Bergbom (AT) lm (DOT) se> wrote in message
news:4088b6e5 (AT) newsgroups (DOT) borland.com...

i := ReadInteger; // reading stream size gives size = 167772161

It should have returned 287, not 167772161.

Why are you calling ReadInteger() manually anyway? If you leave the
AByteCount parameter of ReadStream() set to -1, ReadStream() will call
ReadInteger() internally for you.

----- client -----

FMyBuf.SaveToStream(memStream);
IdTCPClient1.Connect(500);
try
IdTCPClient1.WriteStream(memStream, True, True);
finally
IdTCPClient1.Disconnect;
end;


----- server -----

ReadStream(memStream, -1, False);


Gambit





Back to top
Remy Lebeau (TeamB)
Guest





PostPosted: Fri Apr 23, 2004 7:53 pm    Post subject: Re: Strange behavior sending stream from IdTCPClient to IdTC Reply with quote

"Staffan" <Staffan.Bergbom (AT) lm (DOT) se> wrote


Quote:
// request := Readln;
// -------------ACTIVATING THIS GIVES RIGHT MEMSTREAM SIZE
request := Readln(#13, 10000);
// ------------ ACTIVATING THIS GIVES WRONG MEMSTREAM SIZE


Functionaly, there is zero difference between the two other than the
timeout, since ReadLn() already looks for #13 by default. They should not
be effecting ReadStream() at all either way.

Quote:
if Pos('Integer', request) <> 0 then // INTEGER INPUT
i := ReadInteger
else if Pos('String', request) <> 0 then // STRING INPUT
temp := Readln
else if Pos('MemStream', request) <> 0 then // MEMSTREAM INPUT

Since you are sending binary data to begin with, I would not suggest using
strings to specify the binary type. Generally, it is better to use a
numeric value instead. Not only is it less data to transmit, but it also
allows the use of a 'Case of' block, which is more efficient to execute than
a series of 'if' and Pos() statements.

Quote:
except
on E: Exception do
ShowMessage(Format('Exception %s Occured: %s',
[E.ClassName, E.Message]));
end;
finally
i := memStream.Size;
Panel1.Caption := 'memStream.Size:' + IntToStr(memStream.Size);

On the server end, you can't use ShowMessage() or access GUI components
directly when you are inside a thread. You must synchronize access to them
instead, otherwise you run the risk of either 1) blowing up your code, 2)
deadlocking your code, 3) something else unexpected happening. The VCL is
not thread-safe.

Try this code instead:

--- client ---

const
mtInteger = 1;
mtString = 2;
mtStream = 3;

var
c: Char;
begin
c := mtStream;
IdTCPClient1.WriteBuffer(@c, SizeOf(Char));
IdTCPClient1.WriteStream(memStream, True, True);
end;


--- server ---

const
mtInteger = 1;
mtString = 2;
mtStream = 3;

//...

TPanelCaption = class(TIdSync)
private
FPanel: TPanel
FCaption: String;
public
constructor Create(APanel: TPanel; const ACaption: String);
procedure DoSynchronize; override;
class procedure Update(AThread: TIdPeerThread; APanel: TPanel; const
ACaption: String);
end;

constructor TPanelCaption.Create(AThread: TIdPeerThread; APanel: TPanel;
const ACaption: String);
begin
inherited Create(AThread);
FPanel := APanel;
FCaption := ACaption;
end;

procedure TPanelCaption.DoSynchronize;
begin
FPanel.Caption := FCaption;
end;

procedure TPanelCaption.Update(AThread: TIdPeerThread; APanel: TPanel;
const ACaption: String);
begin
with TPanelCaption.Create(AThread, APanel, ACaption) do
begin
try
Synchronize;
finally
Free;
end;
end;
end;


memStream := nil;
with AThread.Connection do
begin
try
Case ReadChar of
mtInteger: i := ReadInteger;
mtString: temp := ReadLn;
mtStream:
begin
memStream := TMemoryStream.Create;
try
ReadStream(memStream, -1, False);
TPanelCaption.Update(AThread, Panel1,
'memStream.Size:' + IntToStr(memStream.Size));
finally
FreeAndNil(memStream);
end;
end;
else
WriteLn('Unknown Data Type!!!');
end;
except
on E: Exception do begin
Windows.MessageBox(nil, PChar(Format('Exception %s Occured:
%s', [E.ClassName, E.Message])), PChar('Error'), MB_OK);
WriteLn('Error!!!');
end;
end;
end;

Quote:
Can you explain why ReadLn works, but not ReadLn(#13, 10000) ?

There is no reason why it shouldn't work. The only thing I can think of is
if you are corrupting your overall reading of the data by using a timeout
and not handling it properly.


Gambit



Back to top
Staffan
Guest





PostPosted: Fri Apr 23, 2004 10:41 pm    Post subject: Re: Strange behavior sending stream from IdTCPClient to IdTC Reply with quote

Thanks a lot,

I'll dig in to your code suggestion to really understand all parts

Staffan

"Remy Lebeau (TeamB)" <gambit47.no.spam (AT) no (DOT) spam.yahoo.com> skrev i
meddelandet news:4089759d$1 (AT) newsgroups (DOT) borland.com...
Quote:

"Staffan" <Staffan.Bergbom (AT) lm (DOT) se> wrote in message
news:4089121a (AT) newsgroups (DOT) borland.com...

// request := Readln;
// -------------ACTIVATING THIS GIVES RIGHT MEMSTREAM SIZE
request := Readln(#13, 10000);
// ------------ ACTIVATING THIS GIVES WRONG MEMSTREAM SIZE

Functionaly, there is zero difference between the two other than the
timeout, since ReadLn() already looks for #13 by default. They should not
be effecting ReadStream() at all either way.

if Pos('Integer', request) <> 0 then // INTEGER INPUT
i := ReadInteger
else if Pos('String', request) <> 0 then // STRING INPUT
temp := Readln
else if Pos('MemStream', request) <> 0 then // MEMSTREAM INPUT

Since you are sending binary data to begin with, I would not suggest using
strings to specify the binary type. Generally, it is better to use a
numeric value instead. Not only is it less data to transmit, but it also
allows the use of a 'Case of' block, which is more efficient to execute
than
a series of 'if' and Pos() statements.

except
on E: Exception do
ShowMessage(Format('Exception %s Occured: %s',
[E.ClassName, E.Message]));
end;
finally
i := memStream.Size;
Panel1.Caption := 'memStream.Size:' + IntToStr(memStream.Size);

On the server end, you can't use ShowMessage() or access GUI components
directly when you are inside a thread. You must synchronize access to
them
instead, otherwise you run the risk of either 1) blowing up your code, 2)
deadlocking your code, 3) something else unexpected happening. The VCL is
not thread-safe.

Try this code instead:

--- client ---

const
mtInteger = 1;
mtString = 2;
mtStream = 3;

var
c: Char;
begin
c := mtStream;
IdTCPClient1.WriteBuffer(@c, SizeOf(Char));
IdTCPClient1.WriteStream(memStream, True, True);
end;


--- server ---

const
mtInteger = 1;
mtString = 2;
mtStream = 3;

//...

TPanelCaption = class(TIdSync)
private
FPanel: TPanel
FCaption: String;
public
constructor Create(APanel: TPanel; const ACaption: String);
procedure DoSynchronize; override;
class procedure Update(AThread: TIdPeerThread; APanel: TPanel;
const
ACaption: String);
end;

constructor TPanelCaption.Create(AThread: TIdPeerThread; APanel:
TPanel;
const ACaption: String);
begin
inherited Create(AThread);
FPanel := APanel;
FCaption := ACaption;
end;

procedure TPanelCaption.DoSynchronize;
begin
FPanel.Caption := FCaption;
end;

procedure TPanelCaption.Update(AThread: TIdPeerThread; APanel: TPanel;
const ACaption: String);
begin
with TPanelCaption.Create(AThread, APanel, ACaption) do
begin
try
Synchronize;
finally
Free;
end;
end;
end;


memStream := nil;
with AThread.Connection do
begin
try
Case ReadChar of
mtInteger: i := ReadInteger;
mtString: temp := ReadLn;
mtStream:
begin
memStream := TMemoryStream.Create;
try
ReadStream(memStream, -1, False);
TPanelCaption.Update(AThread, Panel1,
'memStream.Size:' + IntToStr(memStream.Size));
finally
FreeAndNil(memStream);
end;
end;
else
WriteLn('Unknown Data Type!!!');
end;
except
on E: Exception do begin
Windows.MessageBox(nil, PChar(Format('Exception %s
Occured:
%s', [E.ClassName, E.Message])), PChar('Error'), MB_OK);
WriteLn('Error!!!');
end;
end;
end;

Can you explain why ReadLn works, but not ReadLn(#13, 10000) ?

There is no reason why it shouldn't work. The only thing I can think of
is
if you are corrupting your overall reading of the data by using a timeout
and not handling it properly.


Gambit





Back to top
Display posts from previous:   
Post new topic   Reply to topic    BorlandTalk.com Forum Index -> Delphi Internet Winsock All times are GMT
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2006 phpBB Group
SEO toolkit © 2004-2006 webmedic.