Sending and receiving a TMemoryStream using IdTCPClient and IdTCPServer

I found Remy Lebeau to demonstrate IdTCP components in XE2, and I wanted to play a little with it. (You can find it here ) I would like to send an image using these components, and the best approach seems to be using TMemoryStream. If I send lines, the connection works fine, the lines are transmitted successfully, however, when I change it to Stream, it does not 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 a stream from the client, nothing observable happens (the breakpoint in OnExecute does not work). However, when you close the programs (after sending the MemoryStream), two things happen:

  • If the client is closed first, only after that the except part is processed (the log shows the โ€œFailed to receiveโ€ error. However, even if I put a breakpoint on the first line of the try-except block, it is somehow skipped and only the error is displayed).
  • If the server is closed first, the IDE does not return back from debugging, the Client does not change its state to disconnected (as usual, when the server shuts down), and after the Client is closed, an access violation gives an error from the Server application. I assume this means that there is a server thread that is still running and maintaining the connection. But no matter how much time I give him, he never completes the task of getting a MemoryStream.

Note. The server uses IdSchedulerOfThreadDefault and IdAntiFreeze , if that matters.

Since I cannot find a reliable source of help for the updated Indy 10 (all this seems to refer to the earlier 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; 

CUSTOMER

 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; 
+4
source share
2 answers

Just use the correct options:

 .IOHandler.Write(ms, 0, true); //true ... indicates WriteByteCount .IOHandler.ReadStream(ms, -1); //-1 ... use ByteCount 
+6
source

Send the stream size up so the server knows how many bytes it should 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 (Resource handling fixed)

 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; 
+3
source

All Articles