首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Indy写入缓冲/高效TCP通信

Indy写入缓冲/高效TCP通信
EN

Stack Overflow用户
提问于 2009-03-03 08:40:12
回答 3查看 15.8K关注 0票数 8

我知道,作为一名新的delphi开发人员,我对questions...but提出了很多问题,我总是会遇到这些问题:)

它使用indy 10处理TCP通信。为了提高通信效率,我将客户端操作请求编码为单字节(在大多数情况下,当然后面跟着其他数据字节,但在本例中只有一个字节)。问题是

代码语言:javascript
复制
var Bytes : TBytes;
...
SetLength (Bytes, 1);
Bytes [0] := OpCode;
FConnection.IOHandler.Write (Bytes, 1);
ErrorCode := Connection.IOHandler.ReadByte;

不会立即发送该字节(至少不会调用服务器执行处理程序)。例如,如果我将“1”更改为“9”,则一切正常。我假设Indy对传出字节进行缓冲,并尝试使用以下命令禁用写缓冲

代码语言:javascript
复制
FConnection.IOHandler.WriteBufferClose;

但这并没有帮助。我如何发送一个字节并确保它被立即发送?还有--我在这里再加一个小问题--使用indy发送整数的最佳方式是什么?不幸的是,我在TIdTCPServer...and的IOHandler中找不到像WriteInteger这样的函数

代码语言:javascript
复制
WriteLn (IntToStr (SomeIntVal))

在我看来效率不是很高。我是在一行中使用多个write命令,还是将内容打包到一个字节数组中并发送一次,这有什么区别吗?

谢谢你的回答!

编辑:我添加了一个提示,我正在使用Indy 10,因为读取和写入过程似乎有了重大变化。

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2009-03-04 03:38:54

默认情况下,写入缓冲处于禁用状态。您可以通过测试fConnection.IOHandler.WriteBufferingActive属性来检查写入缓冲,以查看它在代码中是否处于活动状态。

至于发送整数的最佳方式...“这取决于”你的协议和总体目标。具体地说,使用FConnection.IOHandler.Write(),因为有重载的方法可以写入几乎任何类型的数据,包括整数。

摘自IdIOHandler:

代码语言:javascript
复制
// 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;

您遇到的另一个问题是“我是在一行中使用多个write命令,还是将内容打包到一个字节数组中并发送一次,这是否有区别?”对于大多数情况来说,是的,这是有区别的。对于高度紧张的服务器,你将不得不更多地参与如何来回发送字节,但在这个级别上,你应该将发送抽象为一个单独的协议类型类,该类构建要发送的数据并在突发中发送它,并具有一个接收协议,该协议接收一堆数据并将其作为一个完整的单元进行处理,而不是将事情分解为发送/接收整数、字符、字节数组等。

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

代码语言:javascript
复制
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;

然后通过以下方式发送:

代码语言:javascript
复制
  FConnection.IOHandler.Write(myCommand.Serialize());

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

代码语言:javascript
复制
  myCommand.Deserialize(ReceivedData);
票数 6
EN

Stack Overflow用户

发布于 2009-03-03 09:33:51

我不熟悉Indy,但您可能希望在它的API中查找延迟选项(您可能希望在Indy源代码树中使用grep来查找类似的内容--不区分大小写的“TCP_NODELAY”应该可以做到。)

编辑:指出我所指的属性是TIdIOHandlerSocket.UseNagle --谢谢!

这个问题是TCP本身固有的问题。TCP确实保证数据以与发送时相同的顺序传递,但不保证消息边界。换句话说,源的操作系统、目标的操作系统以及沿途的任何路由器都可以随意合并来自连接的数据包或对其进行分段。您必须将TCP传输视为流,而不是一系列单独的数据包。因此,您必须实现一种机制,通过该机制,您可以分隔各个消息(例如,通过一个幻字节,如果它也可能出现在您的消息数据中,则必须对其进行转义),或者您可以先发送下一条消息的长度,然后发送实际消息。

当我需要在消息边界很重要的地方发送消息时,我总是使用UDP和简单的ACK/重传方案,例如您的情况。可能需要考虑到这一点。UDP更适合于命令消息。

票数 4
EN

Stack Overflow用户

发布于 2009-03-03 09:30:12

听起来你必须刷新你的缓冲区。试试这个:

代码语言:javascript
复制
TIdTCPConnection.FlushWriteBuffer;

如果您不需要写缓冲区,请使用以下命令:

代码语言:javascript
复制
TIdTCPConnection.CancelWriteBuffer;

根据帮助,它首先调用ClearWriteBuffer,以清除缓冲区,然后调用CloseWriteBuffer。

发送整数的最好方法(使用Indy10)是使用TIdIOHandler.Write (根据Indy10的help Write是重载的,以处理不同类型的数据,包括整数)

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/605580

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档