2012-08-28 76 views
4

我在XE2中发现了Remy Lebeau的IdTCP组件的聊天演示,我想稍微玩一下。 (可以找到here)我想用这些组件发送图片,最好的方法似乎是使用TMemoryStream。如果我发送字符串,连接工作正常,字符串传输成功,但是当我将其更改为Stream时,它不起作用。下面是代码:使用IdTCPClient和IdTCPServer发送和接收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; 

客户

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; 

当我尝试发送来自客户端的数据流,没有任何可观察到的情况(断点在OnExecute没有按” t火)。然而,在关闭程序时(发送的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; 

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; 
+0

先发流的大小,这样服务器确切地知道它需要读多少字节。 – whosrdaddy

回答

6

只要使用适当的参数:

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

.IOHandler.ReadStream(ms, -1); //-1 ... use ByteCount 
+0

甚至比我的解决方案更好:) – whosrdaddy

+0

@whosrdaddy:它实际上是一样的,只是这个功能已经包含在内。 –

+0

太棒了,它现在可以工作,即使不需要断开和重新连接客户端。为了正直,我会更新我的问题。 因为你们两个人的答案实际上是一样的,我不知道哪一个给予*接受的答案* ..我会给它较短的版本,但是,不过谢谢,* whosrdaddy * –

3

发送str的大小eam upfront,以便服务器知道它必须读取多少个字节。

服务器:

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; 

客户端(固定的资源处理)

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; 
+0

谢谢,它的工作方式。这两个应用程序仍然“卡住”,只有在退出客户端服务器写入“无法接收”错误。但是,尽管出现这种错误,图片*将被正确保存在硬盘上。所以看起来,传输完成正常,但没有*结束*,由于某种原因 –

+0

服务器试图接收Execute循环中的下一张图片。发送图片后,断开客户端应该解决问题,因为服务器通知关闭的套接字并停止。 – mjn

+0

这真的是正确的方法吗?我的意思是,我可能会发送更多的照片,只能根据客户需求,所以连接和断开所有的时间对我来说似乎有点奇怪。无论如何,只有当数据进入服务器时才会触发OnExecute,它不是一个循环,对吧? –