0

質問が多すぎて申し訳ありませんが、明日(実際には今日私の国では今午前2時です)私が作り始めたものを先生に見せる必要があります。以前の質問で尋ねたようにサーバーからクライアントにデータを送信する必要があります。しかし、その後、サーバーのメモ欄には何も表示されません。memo1.Lines.Add(IntToStr(arrOf[1]));

クライアントでそのように送信しようとしていました

procedure TForm1.btnTestClick(Sender: TObject);
var
  msRecInfo: TMemoryStream;
  arrOf: array of integer; i:integer;
begin
  setLength(arrOf, 11);
  for i := 0 to 10 do
    arrOf[i]:=random(100);

  msRecInfo:= TMemoryStream.Create;

  try
    msRecInfo.Write(arrOf, SizeOf(arrOf));
    idTCPClient1.IOHandler.Write(msRecInfo);
  finally
     msRecInfo.Free;
  end;

end;

サーバー上

procedure TForm1.IdTCPServer1Execute(AContext: TIdContext);
var
   msRecInfo: TMemoryStream;
  arrOf: array of Integer; i:integer;
begin
  msRecInfo:= TMemoryStream.Create;
  try
    AContext.Connection.IOHandler.ReadStream(msRecInfo, -1, False);
    SetLength(arrOf,11);
    msRecInfo.Position := 0;
    msRecInfo.Read(arrOf, SizeOf(arrof));
  finally
    memo1.Lines.Add(IntToStr(arrOf[1]));
    msRecInfo.Free;
  end;    
end;

この問題を解決し、さまざまなタイプ/クラスの配列を送信する方法の例を見つけるのを手伝ってくれませんか?

4

2 に答える 2

3

これがあなたの主な問題です

msRecInfo.Write( arrOf, SizeOf( arrOf ) );

配列のポインターアドレスをストリームに書き込みます...それがあなたの目標だとは思いません。

配列の内容をストリームに入れたい場合は、使用する必要があります

msRecInfo.Write( arrOf[ Low( arrOf ) ], SizeOf( Integer ) * Length( arrOf ) );

なんで?データの最初の位置 (配列の最初の要素) を指す必要があり、データの長さを計算する必要があります。

受信側はまったく同じです

msRecInfo.Read( arrOf[ Low( arrOf ) ], SizeOf( Integer ) * Length( arrOf ) );

PS: これはこの特別なケースではうまくいくかもしれませんが、安全のために、最初にすべてのデータの長さを送信する必要があります。

于 2012-11-21T23:20:47.167 に答える
3

Rufo が既に説明したように、配列の書き込みと読み取りをTMemoryStream正しく行っていません。

さらに悪いことにTMemoryStream、ソケットを介して正しく送信していません。とのデフォルト パラメータは互いに互換性がありませんTIdIOHandler.Write(TStream)TIdIOHandler.ReadStream()デフォルトでは、値を送信Write(TStream) しませんTStream.SizeReadStream()ただし、 (明示的に渡す値と同じ値である)の既定のパラメーターは、最初の数バイトを読み取り、それらを として解釈するように指示しSizeます。これは、この例では非常に間違っています。

代わりにこれを試してください:

procedure TForm1.btnTestClick(Sender: TObject);
var
  msRecInfo: TMemoryStream;
  arrOf: Array of Integer;
  i: Integer;
begin
  SetLength(arrOf, 11);
  for i := Low(arrOf) to High(arrOf) do
    arrOf[i] := random(100);

  msRecInfo := TMemoryStream.Create;
  try
    msRecInfo.WriteBuffer(arrOf[0], Length(arrOf) * SizeOf(Integer));
    IdTCPClient1.IOHandler.Write(msRecInfo, 0, True);
  finally
     msRecInfo.Free;
  end;
end;

procedure TForm1.IdTCPServer1Execute(AContext: TIdContext);
var
  msRecInfo: TMemoryStream;
  arrOf: Array of Integer;
  i: Integer;
begin
  msRecInfo := TMemoryStream.Create;
  try
    AContext.Connection.IOHandler.ReadStream(msRecInfo, -1, False);
    SetLength(arrOf, msRecInfo.Size div SizeOf(Integer));
    if Lenth(arrOf) > 0 then
    begin
      msRecInfo.Position := 0;
      msRecInfo.ReadBuffer(arrOf[0], Length(arrOf) * SizeOf(Integer));
    end;
  finally
    msRecInfo.Free;
  end;    
  ...
end;

または、 を削除してTMemoryStream、個々のInteger値を単独で送信します。

procedure TForm1.btnTestClick(Sender: TObject);
var
  arrOf: Array of Integer;
  i: Integer;
begin
  SetLength(arrOf, 11);
  for i := Low(arrOf) to High(arrOf) do
    arrOf[i] := random(100);

  IdTCPClient1.IOHandler.Write(Length(arrOf));
  for I := Low(arrOf) to High(arrOf) do
    IdTCPClient1.IOHandler.Write(arrOf[i]);
end;

procedure TForm1.IdTCPServer1Execute(AContext: TIdContext);
var
  arrOf: Array of Integer;
  i: Integer;
begin
  i := AContext.Connection.IOHandler.ReadLongInt;
  SetLength(arrOf, i);
  for i := Low(arrOf) to High(arrOf) do
    arrOf[i] := AContext.Connection.IOHandler.ReadLongInt;
  ...
end;

TMemoそうは言っても、イベント ハンドラーで直接アクセスすることは、OnExecuteスレッド セーフではありません。 TIdTCPServerマルチスレッドコンポーネントです。OnExecuteイベントは、メイン スレッドではなく、ワーカー スレッドのコンテキストでトリガーされます。のような UI コンポーネントTMemoは、メイン スレッドの外部から安全にアクセスすることはできません。IndyTIdNotifyまたはTIdSyncクラスを使用して、メイン スレッドと同期できます。たとえば、次のようになります。

type
  TMemoSync = class(TIdSync)
  protected
    FLine: String;
    procedure DoSynchronize; override;
  end;

procedure TMemoSync.DoSynchronize;
begin
  Form1.Memo1.Lines.Add(FLine);
end;

procedure TForm1.IdTCPServer1Execute(AContext: TIdContext);
var
  ...
begin
  ...
  with TMemoSync.Create do try
    FLine := IntToStr(arrOf[1]);
    Synchronize;
  finally
    Free;
  end;
  ...
end;

メイン スレッドと同期しないと、問題が発生する可能性があります。

于 2012-11-22T00:15:32.080 に答える