想想MUD / MUCK,但也许有头像或场所插图。我选择的语言是 ruby 。
我需要处理多个持久连接,并在服务器及其各个客户端之间异步传输数据。必须根据客户端会话中发生的活动保持单个数据库的最新状态。每个客户端会话中的活动可能需要立即更新多个其他客户端(用户进入房间;用户向另一个用户发送私人消息)。
这是目标项目 和 学习项目,所以我的目的是重新发明一两个轮子以了解更多信息并发网络编程。但是,我对并发和网络编程都不熟悉;以前我几乎专门在Web应用程序中的非持久性同步HTTP请求的世界中工作。所以,我想确保我重新发明正确的轮子。
根据emboss的优秀答案,我开始关注某些HTTP服务器的内部情况,因为网络应用程序通常可以避免由于服务器本身抽象问题的彻底解决而导致的线程问题。
我不想使用EventMachine或GServer,因为我还不知道他们做了什么。一旦我对他们的工作方式有了一般意识,他们解决了什么问题以及为什么它们有用,我会对此感到满意。我的目标不是“写游戏”,而是“编写游戏并了解一些低级别的东西是如何工作的”。我也不清楚某些术语的界限;例如,“I / O-unbound apps”是“事件驱动的应用程序”的超集吗?反之亦然?
我当然对实现我的目标的一种正确方法感兴趣,如果它存在,但总体而言我想了解为什么这是正确的方式以及为什么其他方式不太可取。
您可以提供的任何书籍,电子书,在线资源,示例项目或其他花絮都是我真正想要的。
我现在正在做的事情是使用IO#select
来阻止连接套接字列表,超时 0.1 秒。它将读取的任何信息推送到线程安全的读取队列中,然后无论何时达到超时,它都会从线程安全的写入队列中提取数据。我不确定超时是否应该更短。还有第二个线程轮询套接字处理线程的读取队列并处理“请求”。这比我最初的工作方式要好,但仍然可能不太理想。
我在Hacker News上发布了这个问题,并且链接到我正在处理的一些资源;类似的东西会很棒:
答案 0 :(得分:13)
虽然您可能不喜欢听,但我仍然建议您先开始调查HTTP服务器。虽然为他们编程对你来说似乎很无聊,同步和非持久,但这只是因为服务器的创建者完成了他们的工作,以便非常好地隐藏你的血腥细节 - 如果你考虑一下,一个Web服务器是如此<强大>不同步(并不是数百万人不得不等待阅读这篇文章,直到你完成...并发:) ...并且因为这些野兽做得很好(是的,我知道我们对他们大吼大叫,但在一天结束的时候,大多数HTTP服务器都是出色的软件。如果你想了解有效的多线程,这是一个明确的起点。编程语言或游戏的操作系统和实现是另一个很好的来源,但可能会远离您想要实现的目标。
如果你真的打算弄脏你的话,我建议先把自己定位在类似WEBrick的东西上 - 它附带Ruby,并且完全用Ruby实现,所以你将学习所有关于Ruby线程概念的知识。但要注意,您永远不会接近位于C语言服务器上的Rack解决方案的性能,例如thin。
因此,如果您真的想要认真,那么您必须在C(++)中推出自己的服务器实现,如果您打算支持HTTP,可能会支持Rack。我会说,这是一项非常重要的任务,特别是如果您希望最终结果具有竞争力。 C代码可以非常快,但它也很容易变得非常慢,它在于低级别的东西。我们还没有讨论内存管理和安全性。但如果它真的是你的愿望,那就去吧,但我会首先深入了解众所周知的服务器实现以获得灵感。了解它们如何与线程(池)一起工作以及它们如何实现'会话'(您希望持久化)。您希望的所有内容都可以通过HTTP完成,当与智能REST界面一起使用时,甚至更好。支持您提到的所有功能的现有应用程序就是生动的证据。所以走向那个方向并不是完全错误的。
如果您仍想发明自己的专有协议,请将其作为最低可接受的公分母以TCP / IP为基础。超出这个范围将最终出现在您的孩子可能仍会编码的项目中。在网络编程方面,这一点真的很低。
无论您是否将其用作库,请查看EventMachine及其概念模型。在学习/重新发明正确的轮子的背景下,在您的旅程中忽略事件驱动(“非阻塞”)IO将是疏忽的。用于事件驱动编程的开胃菜,将node.js的好处解释为web server。
根据您的要求:异步通信,多个“订阅者”对集中发布的“事件”作出反应;那真的听起来像event-driven/message-based架构的好候选人。
一些可能对您的旅程有所帮助的书籍(仅限Linux / C,但概念是通用的):
(那些是经典)
您可能想要查看的项目:
答案 1 :(得分:3)
我建议您阅读一些关于独角兽网络服务器设计的内容。这应该可以让您深入了解线程与流程讨论。
答案 2 :(得分:2)
我对Ruby不太了解 - 抱歉 - 但我认为架构需要由你的要求驱动(母性,苹果派......我知道)。
如果您正在构建需要扩展到大量用户的东西,那么您的架构需要反映出这一点 - 并且如果您在更多的地方运营,您最终会做出各种各样的决策适度的规模。
响应时间也起着重要作用 - 我认为MUD风格的游戏不是很重要,但对于网络服务器或FPS游戏来说,这是一个很大的问题。
话虽如此 - 我所知道的唯一类似于您所描述的系统使用事件驱动的编程模型 - 客户端触发事件,系统更新其内部状态,并通知受影响的客户端。 “内部状态”实际上存储在一个单独的应用程序中,再次使用套接字进行通信 - 这允许通过添加更多服务器来扩展应用程序以处理客户端交互。不确定你需要那么高的复杂程度。
线程确实是一个真正的问题,它创建了难以测试的代码,因此虽然dash-tom-bang的答案确实有点偏离主题,但可测试性 是一个重要的问题。
答案 3 :(得分:-1)
正确的方法是使用测试驱动的开发。然后,您将在需要发明它的确切时刻发现需要重新发明的东西。
从“连接”测试开始,并断言返回消息“hello,user”。从那里一步一步。