c#中的多部分消息流处理

本文关键字:消息 处理 多部 | 更新日期: 2023-09-27 18:06:19

我需要解析一个包含协议定义的二进制格式消息的TCP数据流,这些消息可能是多部分的,也可能不是。消息中的报头表明消息是否有多个部分(第1部分或第4部分,等等)。我正在用一个消息类成功地解析单部分消息,该消息类将字节数据解码为类成员-这占所有流量的95%左右。

我是c#-dotNet的新手,我在c++中有大部分经验,管理这一点的旧方法是有一个字段端点数组,可以存储对数据结构的引用,当消息在接收端重建时,我可以根据需要增长。我已经研究了c#等效的可能方法,但它们似乎是面向HTTP的,并且使用文件系统进行临时存储,但我正在寻找在内存中构建消息的方法。我对c#类、持久化、垃圾收集等的掌握有限,以至于我不确定一种方法。

我的TCP处理程序有一个回调消息处理程序,解析'abc'协议的消息:

void processTcpPacket(StateObject tcpControl)
{
    abcMessage abc = new abcMessage();
    abc.parse(tcpControl.buffer,tcpControl.size)
    if(abc.complete)
    {
        do something with this message()
    }else if abc.multipart{
        hold this message somewhere until the next part shows up... ?
    }else{
        discard unparseable message()
    }
}

processTcpPacket()是异步的,从多个端点传递消息;每条消息的报头都有完整的源地址和目的地址。该协议将一个长消息分成大约200字节的段,这些段被发送给接收者并重新组装——最大的有效载荷可达~5000字节。

在c++世界中,我会为多部分消息创建一个存储容器,该容器具有发送者的源地址,因此我可以找到正确的容器并不断添加消息部分,直到消息完成,然后处理消息并删除临时容器。我可以使用c#遵循类似的过程吗?

c#中的多部分消息流处理

除非我错过了要点,否则它们都不允许我创建对象来"记住"部分数据,直到下一次异步回调。这个对象必须在回调之外持续存在…

正确…在类级别声明字典,以便它在调用中持续存在,并使用源地址作为键添加"abc"实例。

下面是一些非常粗略的伪代码:

Dictionary<sourceAddress, abcMessage> msgs = new Dictionary<sourceAddress, abcMessage>();
void processTcpPacket(StateObject tcpControl)
{
    if (msgs.ContainsKey(sourceAddress))
    {
        abcMessage abc = msgs[sourceAddress]; // pull partial from the dictionary
        abc.AddParse(tcpControl.buffer,tcpControl.size); // do you have a way to ADD a message yet?
        if(abc.complete)
        {
            do something with this message()
        }
        // if partial, it's already stored in the dictionary, leave it there
    }
    else
    {
        abcMessage abc = new abcMessage();
        abc.parse(tcpControl.buffer,tcpControl.size)
        if(abc.complete)
        {
            do something with this message()
        }else if abc.multipart{
            msgs.Add(sourceAddress, abc); // hold this message somewhere until the next part shows up... ?              
        }else{
            discard unparseable message()
        }
    }
}

不确定要将"sourceAddress"键类型存储为什么。它可以是IP的字符串形式,也可以是唯一标识源的其他方式。