使用IdTCPClient和IdTCPServer发送和接收TMemoryStream

Mar*_*lka 4 delphi tcp indy

我在XE2中找到了Remy Lebeau的IdTCP组件聊天演示,我想稍微玩一下.(可以在这里找到)我想使用这些组件发送图片,最好的方法似乎是使用TMemoryStream.如果我发送字符串,连接工作正常,字符串传输成功,但是当我将其更改为流时,它不起作用.这是代码:

服务器

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;
Run Code Online (Sandbox Code Playgroud)

客户

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;
Run Code Online (Sandbox Code Playgroud)

当我尝试从客户端发送流时,没有任何可观察的事件发生(OnExecute中的断点不会触发).但是,在关闭程序时(发送MemoryStream之后),会发生两件事:

  • 如果客户端先被关闭,那么只有except部件被处理(日志显示'接收失败'错误.但是,即使我在try-except块的第一行放置一个断点,它也会以某种方式被跳过并且只显示错误).
  • 如果首先关闭服务器,则IDE不会从调试返回,客户端不会将其状态更改为断开连接(通常在服务器断开连接时),并且在客户端关闭后也会发生访问冲突错误出现服务器应用.我想这意味着服务器的一个线程仍在运行并维护连接.但无论我给它多少时间,它都永远不会完成接收MemoryStream的任务.

注意:服务器使用IdSchedulerOfThreadDefaultIdAntiFreeze,如果这很重要.

由于我找不到任何可靠的改造Indy 10的帮助来源(它似乎都适用于较旧的Indy 10,甚至Indy 9),我希望你能告诉我出了什么问题.谢谢


- 答案 -

服务器

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;
Run Code Online (Sandbox Code Playgroud)

客户

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;
Run Code Online (Sandbox Code Playgroud)

mar*_*_ja 6

只需使用适当的参数:

.IOHandler.Write(ms, 0, true); //true ... indicates WriteByteCount

.IOHandler.ReadStream(ms, -1); //-1 ... use ByteCount
Run Code Online (Sandbox Code Playgroud)