8

私はたくさんの質問をしています...しかし、新しいDelphi開発者として、私はこれらすべての質問に落ち続けています:)

これは、indy 10 を使用した TCP 通信を扱います。通信を効率化するために、クライアント操作要求を 1 バイトとしてコーディングします (ほとんどのシナリオでは、もちろん他のデータ バイトが続きますが、この場合は 1 バイトのみです)。問題はそれです

var Bytes : TBytes;
...
SetLength (Bytes, 1);
Bytes [0] := OpCode;
FConnection.IOHandler.Write (Bytes, 1);
ErrorCode := Connection.IOHandler.ReadByte;

そのバイトをすぐには送信しません (少なくともサーバーの実行ハンドラは呼び出されません)。たとえば、「1」を「9」に変更すると、すべて正常に動作します。Indy が送信バイトをバッファリングすると想定し、書き込みバッファリングを無効にしようとしました

FConnection.IOHandler.WriteBufferClose;

しかし、それは役に立ちませんでした。1 バイトを送信して、それがすぐに送信されるようにするにはどうすればよいですか? そして - ここにもう 1 つ小さな質問を追加します - indy を使用して整数を送信する最良の方法は何ですか? 残念ながら、 TIdTCPServer の IOHandler に WriteInteger のような関数が見つかりません...そして

WriteLn (IntToStr (SomeIntVal))

私にはあまり効率的ではないようです。複数の書き込みコマンドを続けて使用するか、バイト配列にまとめて一度送信するかに違いはありますか?

回答ありがとうございます。

編集: 読み取りと書き込みの手順に関して大きな変更があるように見えるので、Indy 10 を使用しているというヒントを追加しました。

4

3 に答える 3

6

デフォルトでは、書き込みバッファリングは無効になっています。fConnection.IOHandler.WriteBufferingActive プロパティをテストすることで、書き込みバッファリングがコード内でアクティブかどうかを確認できます。

整数を送信する最良の方法に関しては...プロトコルと全体的な目標に「依存」します。具体的には、FConnection.IOHandler.Write() を使用します。オーバーロードされたメソッドがあり、整数を含むほぼすべてのタイプのデータを書き込むことができます。

IdIOHandler から取得:

// Optimal Extra Methods
//
// These methods are based on the core methods. While they can be
// overridden, they are so simple that it is rare a more optimal method can
// be implemented. Because of this they are not overrideable.
//
//
// Write Methods
//
// Only the ones that have a hope of being better optimized in descendants
// have been marked virtual
procedure Write(const AOut: string; const AEncoding: TIdEncoding = enDefault); overload; virtual;
procedure WriteLn(const AEncoding: TIdEncoding = enDefault); overload;
procedure WriteLn(const AOut: string; const AEncoding: TIdEncoding = enDefault); overload; virtual;
procedure WriteLnRFC(const AOut: string = ''; const AEncoding: TIdEncoding = enDefault); virtual;
procedure Write(AValue: TStrings; AWriteLinesCount: Boolean = False; const AEncoding: TIdEncoding = enDefault); overload; virtual;
procedure Write(AValue: Byte); overload;
procedure Write(AValue: Char; const AEncoding: TIdEncoding = enDefault); overload;
procedure Write(AValue: LongWord; AConvert: Boolean = True); overload;
procedure Write(AValue: LongInt; AConvert: Boolean = True); overload;
procedure Write(AValue: SmallInt; AConvert: Boolean = True); overload;
procedure Write(AValue: Int64; AConvert: Boolean = True); overload;
procedure Write(AStream: TStream; ASize: Int64 = 0; AWriteByteCount: Boolean = False); overload; virtual;

あなたが持っていた別の質問は、「複数の書き込みコマンドを連続して使用するか、バイト配列にまとめて一度送信するかで違いはありますか?」というものでした。ほとんどの場合、はい、違いがあります。非常にストレスの多いサーバーの場合、バイトの送受信方法にさらに関与する必要がありますが、このレベルでは、送信するデータを構築して送信する別のプロトコル タイプ クラスに送信を抽象化する必要があります。バーストし、整数、文字、バイト配列などの送受信に分解するのではなく、一連のデータを受信して​​完全なユニットとして処理する受信プロトコルを備えています。

非常に大まかな簡単な例として:

TmyCommand = class(TmyProtocol)
private
  fCommand:Integer;
  fParameter:String;
  fDestinationID:String;
  fSourceID:String;
  fWhatever:Integer;
public
  property Command:Integer read fCommand write fCommand;
  ...

  function Serialize;
  procedure Deserialize(Packet:String);
end;

function TmyCommand.Serialize:String;
begin
  //you'll need to delimit these to break them apart on the other side
  result := AddItem(Command) + 
            AddItem(Parameter) + 
            AddItem(DestinationID) + 
            AddItem(SourceID) + 
            AddItem(Whatever);
end; 
procedure TMyCommand.Deserialize(Packet:String);
begin
   Command := StrToInt(StripOutItem(Packet));
   Parameter := StripOutItem(Packet);
   DesintationID := StripOutItem(Packet); 
   SourceID := StripOutItem(Packet);
   Whatever := StrToInt(StripOutItem(Packet));
end;

次に、これを次の方法で送信します。

  FConnection.IOHandler.Write(myCommand.Serialize());

反対側では、Indy を介してデータを受信し、

  myCommand.Deserialize(ReceivedData);
于 2009-03-04T03:38:53.707 に答える
4

私は Indy に詳しくありませんが、その API で TCP_NODELAY オプションを探してみてください (そのようなものについては Indy ソース ツリーを grep したいかもしれません - "delay" の場合は大文字と小文字を区別しないはずです)。

編集:ロブ・ケネディは、私が言及していた物件はTIdIOHandlerSocket.UseNagle- ありがとう!

この問題は、TCP の性質に固有のものです。TCP は、送信されたときと同じ順序でデータが配信されることを保証しますが、メッセージの境界は保証しません。言い換えれば、ソース、ターゲット、および途中のルーターのオペレーティングシステムは、接続からのパケットを自由に結合したり、それらを自由にフラグメント化したりできます。TCP 送信は、一連の個々のパケットとしてではなく、ストリームとして見る必要があります。したがって、個々のメッセージを区切るメカニズムを実装する必要があります (たとえば、メッセージ データでも発生する可能性がある場合はエスケープする必要があるマジック バイトによって)、または次のメッセージの長さを送信できます。最初に、次に実際のメッセージ。

あなたの場合のように、メッセージの境界が重要な場所にメッセージを送信する必要がある場合は、単純なACK /再送信スキームと組み合わせてUDPを常に使用してきました。それを考慮したいのかもしれません。UDP は、コマンド メッセージに適しています。

于 2009-03-03T09:33:50.727 に答える
0

バッファをフラッシュする必要があるようです。これを試して:

TIdTCPConnection.FlushWriteBuffer;

書き込みバッファが必要ない場合は、次を使用します。

TIdTCPConnection.CancelWriteBuffer;

ヘルプによると、これはまず ClearWriteBuffer を呼び出してバッファをクリアし、次に CloseWriteBuffer を呼び出します。

(Indy 10 を使用して) 整数を送信する最良の方法は、TIdIOHandler.Write を使用することです (Indy 10 のヘルプによると、Write は整数を含むさまざまな種類のデータを処理するためにオーバーロードされます)。

于 2009-03-03T09:30:12.077 に答える