1

关于如何在维护 KISS 的同时使用 IO 类型的架构实际包含大量连接,我一直在脑海中传递一些想法。通过网络上的示例,似乎大多数使用带有 CONTAINING_RECORD 的双/单链表。而且,作为 IO 服务器的新手(尽管每天都在改进),我也将链表容器用于 IO 架构。

我的问题是,为什么我不能只构建一个大数组并使用 CONTAINING_RECORD,而不是为我的连接使用单/双链表?我可以使用 STL 向量吗?那行得通吗?此外,还有哪些其他类型的容器最适合大型 IO 服务器。

我正在为我的游戏服务器重写服务器架构(经过多次修改),并且这次希望朝着正确的方向前进,因为 id 而不是在不久的将来再次重写它。

感谢您的时间,并回复。

编辑:目前我的服务器架构是(简而言之):

Main thread listening and accepting -> Pass over the socket into a container.
Worker threads(2-3) grab IO events for the container of sockets.
Worker threads Read/Write Data on that container.

主线程和工作线程都使用链表。我想摆脱这个。

4

2 回答 2

1

您的“连接列表”可能会从任何位置删除,而不仅仅是结尾。对于std::vector,删除中间的元素是 O(N) 操作,但对于链表,它可以是 O(1)。(对于单链表,这并不简单,可能需要不方便的 API)。

std::map可能是一个有趣的选择,因为它提供了O(log N)元素的查找和删除。

于 2012-09-11T07:21:35.573 回答
0

与所有数据结构一样,它在很大程度上取决于您想用它做什么。

在之前的工作中,我大部分时间都花在了一个巨大的多线程 C++ 服务器上,在它的 Windows 版本中,它使用了 IO 完成端口(Solaris 后端使用 /dev/poll,这在几个基本方面并没有那么不同)。它使用文件描述符作为键值,将与连接相关的数据结构存储在类似mapSTL 之前的结构中。因此,每当我们在连接上得到一个事件时,我们都可以通过 IO 层传递给我们的描述符来查找它的相关数据结构。新连接很容易处理 - 只需在字典中添加一个条目 - 并且关闭的连接也可以非常简单地清理。

自然地,必须小心对这些结构的跨线程访问和操作顺序——因为 IO 本质上是有效的,所以操作的顺序是至关重要的。幸运的是,IOCP 在将套接字放回 CP 之前不会在另一个线程上为同一个套接字提供另一个事件,但是 Solaris 实现还必须保留一个将文件描述符链接到工作线程的结构,以确保我们只处理每个套接字一次一个事件,并且按照严格的顺序,我们还尝试将套接字的后续事件注入同一个线程,以避免不得不将套接字的结构潜在地切换到另一个处理器上,这对缓存命中率来说是一场灾难。

基本的总结是,我们发现一个设计合理的字典类对这类事情非常有用。

于 2012-09-11T07:07:18.710 回答