Indy写缓冲/高效TCP通信 [英] Indy Write Buffering / Efficient TCP communication

查看:277
本文介绍了Indy写缓冲/高效TCP通信的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我知道,我问了很多问题...但作为一个新的delphi开发者,我总是落在所有这些问题上:)



为了使通信更有效率,我将客户端操作请求编码为单个字节(在大多数情况下,后面跟着其他数据字节,但在这种情况下只有一个字节)。问题是

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

不会立即发送该字节(至少服务器执行处理程序不会被调用)。如果我把'1'改为'9'例如一切工作正常。我假设Indy缓冲输出字节并尝试使用

禁用写缓冲。

  FConnection.IOHandler.WriteBufferClose; 

但它没有帮助。如何发送单个字节并确保立即发送?和 - 我在这里添加另一个小问题 - 什么是使用indy发送整数的最好方法?不幸的是我找不到函数像WriteInteger在TIdTCPServer的IOHandler ...和

  WriteLn(IntToStr(SomeIntVal))

似乎对我来说效率不高。是否在一行中使用多个写入命令,或者在一个字节数组中一起打包,并发送一次?



感谢任何答案!



编辑:我添加了一个提示,我使用Indy 10,因为看起来有关于读写过程的重大更改。

解决方案

默认情况下禁用写入缓冲。你可以通过测试fConnection.IOHandler.WriteBufferingActive属性来检查写入缓冲区是否有效。



至于发送整数的最佳方法。 。这取决于你的协议和总体目标。具体来说,使用FConnection.IOHandler.Write(),因为有重载的方法来写任何类型的数据,包括一个整数。



取自IdIOHandler:

  //最佳额外方法
//
//这些方法基于核心方法。虽然他们可以
//重写,但是它们很简单,很少有一个更优化的方法可以实现
//。因此,它们不可重写。
//
//
//写方法
//
//只有那些希望在后代中更好地优化的方法
/ / has been marked virtual
procedure Write(const AOut:string; const AEncoding:TIdEncoding = enDefault);超载;虚拟;
procedure WriteLn(const AEncoding:TIdEncoding = enDefault);超载;
procedure WriteLn(const AOut:string; const AEncoding:TIdEncoding = enDefault);超载;虚拟;
procedure WriteLnRFC(const AOut:string =''; const AEncoding:TIdEncoding = enDefault);虚拟;
procedure Write(AValue:TStrings; AWriteLinesCount:Boolean = False; const AEncoding:TIdEncoding = enDefault);超载;虚拟;
procedure Write(AValue:Byte);超载;
procedure Write(AValue:Char; const AEncoding:TIdEncoding = enDefault);超载;
procedure Write(AValue:LongWord; AConvert:Boolean = True);超载;
过程Write(AValue:LongInt; AConvert:Boolean = True);超载;
procedure Write(AValue:SmallInt; AConvert:Boolean = True);超载;
procedure Write(AValue:Int64; AConvert:Boolean = True);超载;
procedure Write(AStream:TStream; ASize:Int64 = 0; AWriteByteCount:Boolean = False);超载;虚拟;另一个问题是它是有区别的,无论我在一行中使用多个写命令,还是在一行中使用多个写命令,在一个字节数组中一起打包并发送一次?对于大多数情况,是的,它有所作为。对于高度压缩的服务器,你将不得不更多地涉及字节如何来回发送,但在这个级别你应该抽出你的发送到一个单独的协议类型类,构建要发送的数据,并发送它在一个突发并且具有接收协议,其接收一串数据并将其作为完整单元处理,而不是将事物分解成发送/接收整数,字符,字节阵列等。



作为一个非常粗略的快速示例:

  TmyCommand = class(TmyProtocol)
private
fCommand:Integer;
fParameter:String;
fDestinationID:String;
fSourceID:String;
fWhatever:Integer;
public
属性命令:Integer read fCommand write fCommand;
...

函数Serialize;
procedure Deserialize(Packet:String);
end;

function TmyCommand.Serialize:String;
begin
//你需要对这些进行分隔以在另一侧将它们分开
result:= AddItem(Command)+
AddItem(Parameter)+
AddItem(DestinationID)+
AddItem(SourceID)+
AddItem(Whatever);
end;
procedure TMyCommand.Deserialize(Packet:String);
begin
命令:= StrToInt(StripOutItem(Packet));
参数:= StripOutItem(Packet);
DesintationID:= StripOutItem(Packet);
SourceID:= StripOutItem(Packet);
Whatever:= StrToInt(StripOutItem(Packet));
end;

然后通过以下方式发送:

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

另一方面,您可以通过Indy接收数据,然后

  myCommand.Deserialize(ReceivedData); 


I know, I'm asking a lot of questions...but as a new delphi developer I keep falling over all these questions :)

This one deals with TCP communication using indy 10. To make communication efficient, I code a client operation request as a single byte (in most scenarios followed by other data bytes of course, but in this case only one single byte). Problem is that

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

does not send that byte immediately (at least the servers execute handler is not invoked). If I change the '1' to a '9' for example everything works fine. I assumed that Indy buffers the outgoing bytes and tried to disable write buffering with

FConnection.IOHandler.WriteBufferClose;

but it did not help. How can I send a single byte and make sure that it is immediatly sent? And - I add another little question here - what is the best way to send an integer using indy? Unfortunately I can't find function like WriteInteger in the IOHandler of TIdTCPServer...and

WriteLn (IntToStr (SomeIntVal))

seems not very efficient to me. Does it make a difference whether I use multiple write commands in a row or pack things together in a byte array and send that once?

Thanks for any answers!

EDIT: I added a hint that I'm using Indy 10 since there seem to be major changes concerning the read and write procedures.

解决方案

Write buffering is disabled by default. You can check write buffering to see if it's active in your code by testing the fConnection.IOHandler.WriteBufferingActive property.

As far as the best way to send an integer... 'it depends' on your protocol and overall goals. Specifically, use FConnection.IOHandler.Write() as there are overloaded methods to write just about any type of data, including an integer.

Taken from 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;

Another question you had was "Does it make a difference whether I use multiple write commands in a row or pack things together in a byte array and send that once?" For the majority of cases, yes it makes a difference. For highly stressed servers you are going to have to get more involved in how bytes are sent back and forth, but at this level you should abstract out your sends into a separate protocol type class that builds the data to be sent and sends it in a burst and have a receiving protocol that receives a bunch of data and processes it as a complete unit instead of breaking things down to sending/receiving an integer, character, byte array, etc..

As a very rough quick example:

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;

Then send this via:

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

On the other side you can receive the data via Indy and then

  myCommand.Deserialize(ReceivedData);

这篇关于Indy写缓冲/高效TCP通信的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆