문제

나는 많은 질문을하고 있습니다 ... 그러나 새로운 델파이 개발자로서 나는이 모든 질문에 계속 빠져들고 있습니다 :)

이것은 Indy 10을 사용하여 TCP 커뮤니케이션을 처리합니다. 커뮤니케이션 효율성을 높이기 위해 클라이언트 작업 요청을 단일 바이트로 코딩합니다 (대부분의 시나리오에서 다른 데이터 바이트가 이어지지만이 경우에는 단일 바이트 만). 문제는 그게됩니다

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

해당 바이트를 즉시 보내지 않습니다 (적어도 서버가 핸들러가 호출되지 않음). 예를 들어 '1'을 '9'로 변경하면 모든 것이 잘 작동합니다. 나는 인디가 나가는 바이트를 완충하고

FConnection.IOHandler.WriteBufferClose;

그러나 그것은 도움이되지 않았습니다. 단일 바이트를 어떻게 보내고 즉시 전송되도록 할 수 있습니까? 그리고 여기에 또 다른 작은 질문을 추가합니다 - Indy를 사용하여 정수를 보내는 가장 좋은 방법은 무엇입니까? 불행히도 나는 tidtcpserver의 iohandler에서 WriteInteger와 같은 기능을 찾을 수 없습니다 ... 그리고

WriteLn (IntToStr (SomeIntVal))

나에게는 그다지 효율적이지 않은 것 같습니다. 연속으로 여러 쓰기 명령을 사용하거나 바이트 배열로 물건을 포장하고 한 번 보내 든 차이가 있습니까?

답변 주셔서 감사합니다!

편집 : 읽기 및 쓰기 절차에 관한 주요 변경 사항이있는 것처럼 보이기 때문에 Indy 10을 사용하고 있다는 힌트를 추가했습니다.

도움이 되었습니까?

해결책

쓰기 버퍼링은 기본적으로 비활성화됩니다. FCONNECTION.IOHANDLER.WRITEBUFFERINGACTIVE 속성을 테스트하여 코드에서 활성화되어 있는지 확인하기 위해 쓰기 버퍼링을 확인할 수 있습니다.

정수를 보내는 가장 좋은 방법까지는 ... '프로토콜과 전반적인 목표에 의존합니다. 구체적으로, 정수를 포함하여 거의 모든 유형의 데이터를 작성할 수있는 과부하 메소드가 있으므로 fconnection.iohandler.write ()를 사용하십시오.

IdioAndler에서 가져온 :

// 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);

다른 팁

나는 Indy에 익숙하지 않지만 TCP_NODELAY 옵션을 위해 API를 둘러보고 싶을 수도 있습니다 ( "Delay"에 대해 인감이없는 경우 Indy 소스 트리를 Grep을 원할 수도 있습니다.)

편집하다: 롭 케네디 내가 언급 한 재산은 TIdIOHandlerSocket.UseNagle - 감사해요!

문제는 TCP의 특성에 내재되어 있습니다. TCP는 방출 된 것과 동일한 순서로 데이터 전달을 보장하지만 ~ 아니다 메시지 경계를 보장합니다. 다시 말해, 소스의 운영 체제, 대상 및 길을 따라 라우터는 연결에서 패킷을 합산하거나 마음대로 파편화 할 수 있습니다. TCP 전송을 스트림으로보아야합니다. ~ 아니다 일련의 개별 패킷으로. 따라서 개별 메시지를 구분하는 메커니즘을 구현해야합니다 (예 : Magic Byte, 예를 들어 메시지 데이터에서 발생할 수있는 경우 탈출해야 함). 다음 메시지의 길이를 보낼 수 있습니다. 먼저, 실제 메시지입니다.

나는 항상 메시지 경계가 중요한 경우 메시지를 보내야 할 때 순진한 ACK/Retransmission 구성표와 결합 된 UDP를 항상 사용했습니다. 그것을 고려하고 싶을 수도 있습니다. UDP는 명령 메시지에 훨씬 더 적합합니다.

버퍼를 플러시 해야하는 것 같습니다. 이 시도:

TIdTCPConnection.FlushWriteBuffer;

쓰기 버퍼를 원하지 않으면 다음을 사용하십시오.

TIdTCPConnection.CancelWriteBuffer;

도움말에 따르면, 이것은 먼저 ClearwriteBuffer를 호출하여 버퍼를 지우고 CloseWriteBuffer를 호출합니다.

정수를 보내는 가장 좋은 방법 (Indy 10 사용)은 TidioAndler.write를 사용하는 것입니다 (Indy 10 Help Write에 따르면 정수를 포함하여 다양한 종류의 데이터를 처리하도록 과부하가 표시됨)

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top