2

我使用 Net.Sockets.Socket 类来编写 TCP 服务器。由于 TCP 在流上运行,因此需要一种方法来将消息彼此分开。(有关详细信息,请参阅 Stephen Cleary 在他的博客中的消息框架帖子

我想要实现的是编写一个支持自定义消息帧协议的 TCP 服务器类。此类的示例初始化如下:

var receiveDelimiter = Encoding.UTF8.GetBytes("[END]");
var sendDelimiter = Encoding.UTF8.GetBytes("\r\n");
var protocol = new DelimiterFramingProtocol(receiveDelimiter, sendDelimiter);
var server = new Server(protocol);
server.Start(port);

该协议应该从抽象类 MessageFramingProtocol 派生,并且服务器应该能够使用它来分隔消息。在上面的示例中,如果接收到分隔符(即“[END]”),服务器应该只触发它的 DataReceived 事件,并且 DataReceived 的参数应该只有在分隔符之前的消息部分。如果在分隔符之后收到更多字节,则服务器应存储它们并仅在再次收到分隔符时触发 DataReceived。服务器还应该在它发送的每条消息之后发送 sendDelimiter。

我需要的不是整个服务器类或任何协议类。我需要的是一个模板,一个设计建议。假设我在服务器类中有一个名为 Protocol 的 FramingProtocol 类型的属性,我如何在服务器类的接收和发送操作中使用它?它应该具有哪些抽象方法/属性来提供您在上面看到的灵活性?我应该能够编写派生自 FramingProtocol 的自定义协议类。他们可以使用分隔符、长度前缀,或者其他自定义方法来分隔消息。

4

1 回答 1

1

我不会只使用一个传递给服务器的协议实例——它需要很多。为服务器提供一个工厂类,它要么创建新的协议实例,要么将它们从启动时创建和填充的池中分离出来。

我通常做的是这样的:

RX:提供一个“int Protocol::addBytes(char *data,int len)”函数。输入原始 rx 数据的地址和长度,该函数返回 -1,(意味着它在没有完全组装协议单元的情况下消耗了所有原始数据),或者一个正整数,即在该点消耗的数据的索引它组装了一个有效的PDU。如果实例设法组装一个 PDU,它可以被进一步处理,(例如,触发一个 'DataReceived(Protocol *thisPDU)' 事件并创建一个新的协议实例,(或分离),并加载剩余的原始数据.

TX:提供,(很可能重载),'bool Protocol::loadFrom(SomeDataClass * outData, OutStreamClass *outStream)' 方法,可以将来自任何来源的数据加载到内部成员变量中,以便存在完整的数据集以生成序列化PDU,(如果存在某些问题,则返回 false 或引发异常 - 例如,提供的数据未通过完整性检查)。如果未检测到错误,则实例将序列化数据从传递的“outStream”流/socket/buffer+len 中驱动出来。

于 2012-08-02T15:04:41.170 回答