在C++中创建一个简单的数据包路由器,如何跟踪"客户端"?



我需要一个类Router来接收IP数据包,解析它们并发送到客户端(从类Client(。当然,每个Client都必须告诉Router他们想要接收特定端口的数据包。

template <class T>
class Router
{
public:
//Packets arrive from the world to a Client
virtual bool onReceivePacket(Packet<T>::Ptr packet);
//Packets arrive from a Client to the world
virtual void onSendPacket(Packet<T>::Ptr packet);
protected:
std::unordered_map<int, std::shared_ptr<Client>> tcpRoutingTable;
std::unordered_map<int, std::shared_ptr<Client>> udpRoutingTable;
}

Router的界面非常简单。有人会用来自世界的数据包调用onReceivePacketRouter将提取数据包的目标端口,如果是TCP或UDP,它将通过在客户端上调用onReceive来相应地路由到客户端。例:

auto client = tcpRoutingTable.at(packet->tcpDestination());
client->onReceive(packet);

但是,有两件事困扰着我:

1(如何保持RouterClient之间的关系?如果我只是做一个Client并将其订阅到Router,那么Router还必须在Client中包含指向自身的指针。这种关系非常脆弱,如果ClientRouter消失,它将以不确定的行为结束。此外,通过简单地在ClientRouter上使用shared_ptr,我们得到了shared_ptr递归的问题,这些相互包含,因此永远不会消失。

2(unordered_map是路由数据包的最佳方式吗?我认为没有比简单地检查整数并发送到特定客户端更快的方法了。然而,第一个问题的答案可能会改变这个模型。

如您所见,Router是单线程的,因为使用来自世界的数据包调用Router的东西也是单线程的。但是我可以从多个线程中受益吗?

以下是技术答案,考虑到您更了解您的设计目标和限制 - 您强调简单性。

  1. std::weak_ptr可用于中断由 std::shared_ptr 管理的对象形成的引用循环。

标准::weak_ptr

由于您正在考虑并发,请记住以下几点:实现weak_ptr的前身(Boost 库(直接表示weak_ptr提供了非常有限的操作子集,因为在多线程程序中访问其存储的指针通常是危险的。您的 std 实施可能会继承相同的困难 - 请在单独的问题中进行调查或询问。

  1. 在内部,unordered_map中的元素根据其哈希值组织到存储桶中,以允许直接按其键值快速访问单个元素(平均平均时间复杂度恒定(。因此,从性能的角度来看,unordered_map的使用很有吸引力。

最新更新