I found Remy Lebeau's chat demo of IdTCP components in XE2 and I wanted to play with it a little bit. (It can be found here) I would like to send a picture using these components and the best approach seems to be using TMemoryStream. If I send strings, the connection works fine, the strings are transmitted successfully, however when I change it to Stream instead, it doesn't work. Here is the code:
Server
procedure TMainForm.IdTCPServerExecute(AContext: TIdContext);
var rcvdMsg: string;
ms:TMemoryStream;
begin
// This commented code is working, it receives and sends strings.
// rcvdMsg:=AContext.Connection.IOHandler.ReadLn;
// LogMessage('<ServerExec> '+rcvdMsg);
//
// TResponseSync.SendResponse(AContext, rcvdMsg);
try
ms:=TMemoryStream.Create;
AContext.Connection.IOHandler.ReadStream(ms);
ms.SaveToFile('c:\networked.bmp');
except
LogMessage('Failed to receive',clred);
end;
end;
Client
procedure TfrmMain.Button1Click(Sender: TObject);
var ms: TMemoryStream;
bmp: TBitmap;
pic: TPicture;
s: string;
begin
// Again, this code is working for sending strings.
// s:=edMsg.Text;
// Client.IOHandler.WriteLn(s);
ms:=TMemoryStream.Create;
pic:=TPicture.Create;
pic.LoadFromFile('c:\Back.png');
bmp:=TBitmap.Create;
bmp.Width:=pic.Width;
bmp.Height:=pic.Height;
bmp.Canvas.Draw(0,0,pic.Graphic);
bmp.SaveToStream(ms);
ms.Position:=0;
Client.IOHandler.Write(ms);
ms.Free;
end;
When I try to send the stream from the client, nothing observable happens (breakpoint in the OnExecute doesn't fire). However, when closing the programs(after sending the MemoryStream), two things happen:
except
part get processed (the log displays the 'Failed to receive' error. However, even if I place a breakpoint on the first line of the try-except block, it somehow gets skipped and only the error is displayed).Note: The server uses IdSchedulerOfThreadDefault
and IdAntiFreeze
, if that matters.
As I can't find any reliable source of help for the revamped Indy 10 (it all appears to apply for the older Indy 10, or even Indy 9), I hope you can tell me what is wrong. Thanks
- ANSWER -
SERVER
procedure TMainForm.IdTCPServerExecute(AContext: TIdContext);
var size: integer;
ms:TMemoryStream;
begin
try
ms:=TMemoryStream.Create;
size:=AContext.Connection.IOHandler.ReadLongInt;
AContext.Connection.IOHandler.ReadStream(ms, size);
ms.SaveToFile('c:\networked.bmp');
except
LogMessage('Failed to receive',clred);
end;
end;
CLIENT
procedure TfrmMain.Button1Click(Sender: TObject);
var ms: TMemoryStream;
bmp: TBitmap;
pic: TPicture;
begin
ms:=TMemoryStream.Create;
pic:=TPicture.Create;
pic.LoadFromFile('c:\Back.png');
bmp:=TBitmap.Create;
bmp.Width:=pic.Width;
bmp.Height:=pic.Height;
bmp.Canvas.Draw(0,0,pic.Graphic);
bmp.SaveToStream(ms);
ms.Position:=0;
Client.IOHandler.Write(ms, 0, True);
ms.Free;
end;
Just use the proper parameters:
.IOHandler.Write(ms, 0, true); //true ... indicates WriteByteCount
.IOHandler.ReadStream(ms, -1); //-1 ... use ByteCount
Send the size of the stream upfront so that the server knows how many bytes it must read.
Server:
procedure TMainForm.IdTCPServerExecute(AContext: TIdContext);
var rcvdMsg: string;
ms:TMemoryStream;
size : integer;
begin
// This commented code is working, it receives and sends strings.
// rcvdMsg:=AContext.Connection.IOHandler.ReadLn;
// LogMessage('<ServerExec> '+rcvdMsg);
//
// TResponseSync.SendResponse(AContext, rcvdMsg);
try
ms:=TMemoryStream.Create;
try
size := AContext.Connection.IOHandler.ReadLongint;
AContext.Connection.IOHandler.ReadStream(ms, size, false);
ms.SaveToFile('c:\networked.bmp');
finally
ms.Free;
end;
except
LogMessage('Failed to receive',clred);
end;
end;
Client (Fixed resource handling)
procedure TfrmMain.Button1Click(Sender: TObject);
var ms: TMemoryStream;
bmp: TBitmap;
pic: TPicture;
s: string;
begin
// Again, this code is working for sending strings.
// s:=edMsg.Text;
// Client.IOHandler.WriteLn(s);
ms:=TMemoryStream.Create;
pic:=TPicture.Create;
bmp:=TBitmap.Create;
try
pic.LoadFromFile('c:\Back.png');
bmp.Width:=pic.Width;
bmp.Height:=pic.Height;
bmp.Canvas.Draw(0,0,pic.Graphic);
bmp.SaveToStream(ms);
ms.Position:=0;
Client.IOHandler.Write(ms.Size);
Client.IOHandler.Write(ms);
finally
ms.Free;
bmp.Free;
pic.Free;
end;
end;
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With