Rufo が既に説明したように、配列の書き込みと読み取りをTMemoryStream
正しく行っていません。
さらに悪いことにTMemoryStream
、ソケットを介して正しく送信していません。とのデフォルト パラメータは互いに互換性がありませんTIdIOHandler.Write(TStream)
。TIdIOHandler.ReadStream()
デフォルトでは、値を送信Write(TStream)
しませんTStream.Size
。ReadStream()
ただし、 (明示的に渡す値と同じ値である)の既定のパラメーターは、最初の数バイトを読み取り、それらを として解釈するように指示し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;
メイン スレッドと同期しないと、問題が発生する可能性があります。