 |
BorlandTalk.com Borland discussion newsgroups
|
| View previous topic :: View next topic |
| Author |
Message |
Staffan Guest
|
Posted: Fri Apr 23, 2004 6:25 am Post subject: Strange behavior sending stream from IdTCPClient to IdTCPSer |
|
|
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
|
Posted: Fri Apr 23, 2004 6:27 am Post subject: Re: Strange behavior sending stream from IdTCPClient to IdTC |
|
|
"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
|
Posted: Fri Apr 23, 2004 12:54 pm Post subject: Re: Strange behavior sending stream from IdTCPClient to IdTC |
|
|
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
|
Posted: Fri Apr 23, 2004 7:53 pm Post subject: Re: Strange behavior sending stream from IdTCPClient to IdTC |
|
|
"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
|
Posted: Fri Apr 23, 2004 10:41 pm Post subject: Re: Strange behavior sending stream from IdTCPClient to IdTC |
|
|
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 |
|
 |
|
|
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
|
|