TCP服务器/客户端的自定义消息成帧协议

时间:2012-08-02 14:27:58

标签: c# sockets asynchronous

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

我想要实现的是编写一个支持自定义消息成帧协议的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类型的属性,我如何在Server类中接收和发送操作时使用它?它应该具有哪些抽象方法/属性来提供您在上面看到的灵活性?我应该能够编写派生自FramingProtocol的自定义协议类。他们可能会使用分隔符,长度前缀,两者或其他自定义方法来分隔消息。

1 个答案:

答案 0 :(得分:1)

我不会只使用一个传递给服务器的Protocol实例 - 它需要很多。为服务器提供工厂类,该工厂类可以创建新的Protocol实例,也可以从启动时创建和填充的池中删除它们。

我通常做的是这样的事情:

RX: 提供'int Protocol :: addBytes(char * data,int len)'函数。使用原始rx数据的地址和长度,该函数返回-1,(表示它已经消耗了所有原始数据而没有完全组装协议单元),或者是一个正整数,它是该点消耗的数据的索引它组装了一个有效的PDU。如果实例设法组装PDU,则可以对其进行进一步处理(例如,触发到'DataReceived(Protocol * thisPDU)'事件并创建(或取消)最新的Protocol实例,并加载剩余的原始数据

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

相关问题