5

Indy TCP 接続に問題があります。Indy 10 で Turbo Delphi 2006 を使用しています。複数の TCP パッケージを idTCPClient から idTCPServer に送信したいと考えています。

パッケージを 1 つだけ送信する場合、または関数の 2 つの呼び出しの間に sleep(100) コマンドを挿入する場合は、問題なく動作します。しかし、この関数を頻繁に呼び出すと、サーバーの onExecute が毎回呼び出されるわけではありません。

送信するための私のコード:

procedure SendData(var data: TIdBytes) ;
begin
  FormMain.IdTCPClient.Connect ;
  FormMain.IdTCPClient.Socket.Write(data);
  FormMain.IdTCPClient.Disconnect ;
end ;

この関数を数回 (1 秒間に 5 ~ 10 回) 呼び出して、サーバー アプリケーションでこれらすべてのパッケージを処理したいと考えています。

procedure TFormMain.IdTCPServerMainExecute(AContext: TIdContext);
var
  data: TIdBytes ;
begin
  AContext.Connection.IOHandler.ReadBytes(data, 4, false)
  // processing data
end

事前にご回答いただきありがとうございます。

4

1 に答える 1

5

を呼び出すたびにConnect()、新しい接続が作成され、TIdTCPServerその接続を処理するために新しいスレッドが開始されます(つまり、スレッドプールを有効にしない限り)。それはあなたが本当に欲しいものですか?クライアントに一定期間接続を開いたままにして、既存の接続を可能な限り再利用する方が効率的です。しばらくアイドル状態になっている場合など、本当に必要なくなった場合にのみ接続を切断してください。新しい接続を確立することは、両端でコストのかかる操作であるため、そのオーバーヘッドを可能な限り減らす必要があります。

クライアント側では、を呼び出すとWrite(data)、全体が送信されTIdBytesますが、その長さTIdBytesはサーバーに送信されないため、予想されるバイト数がわかります。 TIdIOHandler.Write(TIdBytes)あなたのためにそれをしません、あなたはそれを手動でしなければなりません。

サーバー側ではReadBytes()、一度に4バイトのみを読み取るように指示しています。4バイトの各ブロックの後、OnExecuteイベントハンドラーを終了し、次の4バイトのブロックを読み取るためにイベントハンドラーが再度呼び出されるのを待ちます。クライアントのソースの長さがTIdBytes4の偶数倍でない限り、 ReadBytes()4バイト未満のクライアントの最後のブロックを読み取ろうとすると、例外が発生し(サーバーが接続を切断します)、サーバーコードは受信しません。そのブロック。

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

procedure SendData(var data: TIdBytes) ; 
begin 
  FormMain.IdTCPClient.Connect; 
  try
    FormMain.IdTCPClient.IOHandler.Write(Longint(Length(data))); 
    FormMain.IdTCPClient.IOHandler.Write(data); 
  finally
    FormMain.IdTCPClient.Disconnect; 
  end;
end; 

procedure TFormMain.IdTCPServerMainExecute(AContext: TIdContext); 
var 
  data: TIdBytes; 
begin 
  with AContext.Connection.IOHandler do
    ReadBytes(data, ReadLongint, false);
  // process data 
end;

そうは言っても、TIdBytes長さを送信するようにクライアントコードを変更することが何らかの理由でオプションではない場合は、代わりにこのサーバーコードを使用してください。

procedure TFormMain.IdTCPServerMainExecute(AContext: TIdContext); 
var 
  LBytes: Integer;
  data: TIdBytes; 
begin 
  // read until disconnected. returns -1 on timeout, 0 on disconnect
  repeat until AContext.Connection.IOHandler.ReadFromSource(False, 250, False) = 0;
  AContext.Connection.IOHandler.InputBuffer.ExtractToBytes(data);
  // process data 
end;

または:

procedure TFormMain.IdTCPServerMainExecute(AContext: TIdContext); 
var 
  strm: TMemoryStream;
  data: TIdBytes;
begin 
  strm := TMemoryStream.Create;
  try
    // read until disconnected
    AContext.Connection.IOHandler.ReadStream(strm, -1, True);
    strm.Position := 0;
    ReadTIdBytesFromStream(strm, data, strm.Size);
  finally
    strm.Free;
  end;
  // process data 
end;

または:

procedure TFormMain.IdTCPServerMainExecute(AContext: TIdContext); 
var 
  strm: TMemoryStream;
begin 
  strm := TMemoryStream.Create;
  try
    // read until disconnected
    AContext.Connection.IOHandler.ReadStream(strm, -1, True);
    // process strm.Memory up to strm.Size bytes
  finally
    strm.Free;
  end;
end;
于 2012-02-07T01:47:15.173 に答える