4

XE2 の IdTCP コンポーネントに関する Remy Lebeau のチャット デモを見つけたので、少し試してみたいと思いました。(ここにあります) これらのコンポーネントを使用して画像を送信したいのですが、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 のブレークポイントが起動しません)。ただし、(MemoryStream を送信した後) プログラムを閉じると、次の 2 つのことが起こります。

  • クライアントが最初に閉じられた場合にのみ、そのexcept部分が処理されます (ログには「受信に失敗しました」というエラーが表示されます。ただし、try-except ブロックの最初の行にブレークポイントを配置しても、どういうわけかスキップされ、エラーのみが表示されます)。
  • サーバーが最初に閉じられた場合、IDE はdebugから戻らず、クライアントはその状態を切断に変更せず(サーバーが切断されたときに通常行われるように)、クライアントが閉じられた後も、からのアクセス違反エラーが発生します。サーバーアプリが表示されます。これは、サーバーのスレッドがまだ実行されており、接続を維持していることを意味していると思います。しかし、どれだけ時間をかけても、MemoryStream を受信するタスクを完了することはありません。

注: サーバーは、問題がある場合はIdSchedulerOfThreadDefaultとを使用しますIdAntiFreeze

改良された 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;

クライアント

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

2 に答える 2

6

適切なパラメータを使用するだけです。

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

.IOHandler.ReadStream(ms, -1); //-1 ... use ByteCount
于 2012-08-28T14:18:23.303 に答える
3

サーバーが読み取らなければならないバイト数を認識できるように、ストリームのサイズを前もって送信します。

サーバ:

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;
于 2012-08-28T14:01:13.127 に答える