想想 MUD/MUCK,但可能还有头像或现场插图。我选择的语言是 ruby。
我需要处理多个持久连接,数据在服务器和它的各种客户端之间异步传输。单个数据库必须根据客户端 session 中发生的事件保持最新。每个客户端 session 中的事件可能需要立即更新多个其他客户端(用户进入房间;用户向另一个用户发送私有(private)消息)。
这是一个目标项目和一个学习项目,所以我打算重新发明一两个轮子来了解更多关于并发网络编程。但是,我对并发编程和网络编程都不熟悉;以前,我几乎只在 Web 应用程序中的非持久同步 HTTP 请求领域工作。所以,我想确保我正在重新发明正确的轮子。
根据 emboss的出色回答,我已经开始研究某些 HTTP 服务器的内部结构,因为 Web 应用程序通常可以避免线程问题,因为服务器本身将问题抽象得非常彻底。
我不想使用 EventMachine 或 GServer,因为我还不明白它们的作用。一旦我对它们的工作原理、它们解决的问题以及它们的用途有了大致的了解,我就会对它感到满意。我在这里的目标不是“编写游戏”,而是“编写游戏并学习一些较低级别的东西是如何工作的”。我也不清楚某些术语的界限;例如,“I/O 非绑定(bind)应用程序”是“事件驱动应用程序”的超集吗?反之亦然?
我当然对实现我的目标的唯一正确方法感兴趣(如果存在的话),但总的来说,我想了解为什么这是正确的方法,以及为什么其他方法不太可取。 p>
您可以推荐的任何书籍、电子书、在线资源、示例项目或其他花絮都是我真正想要的。
我现在做事的方式是使用IO#select 来阻止连接的套接字列表,超时为0.1 秒。它将读取的任何信息推送到线程安全的读取队列中,然后每当超时时,它都会从线程安全的写入队列中提取数据。我不确定超时是否应该更短。还有第二个线程轮询套接字处理线程的读取队列并处理“请求”。这比我最初的工作方式要好,但仍可能不理想。
我在 Hacker News 上发布了这个问题,并获得了一些我正在研究的资源的链接;任何类似的东西都会很棒:
最佳答案
虽然您可能不喜欢听,但我仍然建议您首先开始研究 HTTP 服务器。尽管为他们编程对你来说似乎很无聊、同步和非持久,但这只是因为服务器的创建者做了他们的工作,非常好地向你隐藏了血淋淋的细节——如果你想一想,一个网络服务器是如此< strong="">不同步(并不是说数百万人必须等到你读完这篇文章...并发:) ...并且因为这些野兽做得很好(是的,我知道我们对他们大吼大叫,但归根结底,大多数 HTTP 服务器都是出色的软件)如果您想了解高效的多线程,这是研究的明确起点。操作系统和编程语言或游戏的实现是另一个很好的来源,但可能与您打算实现的目标相去甚远。
如果你真的打算弄脏你的手指,我建议你把自己定位在类似 WEBrick 的地方。首先 - 它与 Ruby 一起发布并且完全在 Ruby 中实现,因此您将在那里学习所有关于 Ruby 线程的概念。但请注意,您永远无法接近 Rack 解决方案的性能,该解决方案位于以 C 语言实现的 Web 服务器之上,例如 thin。 .
所以如果你真的想认真,你必须在 C(++) 中推出你自己的服务器实现,并且可能让它支持 Rack,如果你打算支持 HTTP。我会说这是一项艰巨的任务,特别是如果您希望最终结果具有竞争力。 C 代码可以非常快,但也很容易变得非常慢,这是低级代码的本质。我们还没有讨论内存管理和安全性。但如果这真的是你的愿望,那就去做吧,但我会首先深入研究众所周知的服务器实现以获得灵感。查看它们如何使用线程(池化)以及它们如何实现“ session ”(您想要持久性)。你想要的所有事情都可以用 HTTP 完成,当与一个聪明的 REST 接口(interface)一起使用时甚至更好,支持你提到的所有特性的现有应用程序就是活生生的证明。因此朝这个方向前进并非完全错误。
如果您仍想发明自己的专有协议(protocol),请将其基于 TCP/IP 作为可接受的最低公分母。超越这一点将最终导致您的孙子孙女可能仍在编写的项目。在网络编程方面,这真的是我敢于尝试的最低水平。
无论您是否将其用作库,请查看 EventMachine 及其概念模型。在了解/重新发明正确 轮子的背景下,在您的旅程中忽视事件驱动(“非阻塞”)IO 是一种疏忽。事件驱动编程的开胃菜,将 node.js 的优势解释为 web server .
根据您的要求:异步通信,多个“订阅者”对集中发布的“事件”作出 react ;好吧,这听起来真的很适合 event-driven/message-based建筑学。
一些可能对你的旅程有帮助的书(仅限Linux/C,但概念是通用的):
(那些都是经典)
您可能想要查看的项目:
关于ruby - 我应该如何构建我的(moSTLy)基于文本的游戏服务器?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6849239/
我正在学习如何使用Nokogiri,根据这段代码我遇到了一些问题:require'rubygems'require'mechanize'post_agent=WWW::Mechanize.newpost_page=post_agent.get('http://www.vbulletin.org/forum/showthread.php?t=230708')puts"\nabsolutepathwithtbodygivesnil"putspost_page.parser.xpath('/html/body/div/div/div/div/div/table/tbody/tr/td/div
总的来说,我对ruby还比较陌生,我正在为我正在创建的对象编写一些rspec测试用例。许多测试用例都非常基础,我只是想确保正确填充和返回值。我想知道是否有办法使用循环结构来执行此操作。不必为我要测试的每个方法都设置一个assertEquals。例如:describeitem,"TestingtheItem"doit"willhaveanullvaluetostart"doitem=Item.new#HereIcoulddotheitem.name.shouldbe_nil#thenIcoulddoitem.category.shouldbe_nilendend但我想要一些方法来使用
我有一个字符串input="maybe(thisis|thatwas)some((nice|ugly)(day|night)|(strange(weather|time)))"Ruby中解析该字符串的最佳方法是什么?我的意思是脚本应该能够像这样构建句子:maybethisissomeuglynightmaybethatwassomenicenightmaybethiswassomestrangetime等等,你明白了......我应该一个字符一个字符地读取字符串并构建一个带有堆栈的状态机来存储括号值以供以后计算,还是有更好的方法?也许为此目的准备了一个开箱即用的库?
我有一个Ruby程序,它使用rubyzip压缩XML文件的目录树。gem。我的问题是文件开始变得很重,我想提高压缩级别,因为压缩时间不是问题。我在rubyzipdocumentation中找不到一种为创建的ZIP文件指定压缩级别的方法。有人知道如何更改此设置吗?是否有另一个允许指定压缩级别的Ruby库? 最佳答案 这是我通过查看rubyzip内部创建的代码。level=Zlib::BEST_COMPRESSIONZip::ZipOutputStream.open(zip_file)do|zip|Dir.glob("**/*")d
类classAprivatedeffooputs:fooendpublicdefbarputs:barendprivatedefzimputs:zimendprotecteddefdibputs:dibendendA的实例a=A.new测试a.foorescueputs:faila.barrescueputs:faila.zimrescueputs:faila.dibrescueputs:faila.gazrescueputs:fail测试输出failbarfailfailfail.发送测试[:foo,:bar,:zim,:dib,:gaz].each{|m|a.send(m)resc
很好奇,就使用rubyonrails自动化单元测试而言,你们正在做什么?您是否创建了一个脚本来在cron中运行rake作业并将结果邮寄给您?git中的预提交Hook?只是手动调用?我完全理解测试,但想知道在错误发生之前捕获错误的最佳实践是什么。让我们理所当然地认为测试本身是完美无缺的,并且可以正常工作。下一步是什么以确保他们在正确的时间将可能有害的结果传达给您? 最佳答案 不确定您到底想听什么,但是有几个级别的自动代码库控制:在处理某项功能时,您可以使用类似autotest的内容获得关于哪些有效,哪些无效的即时反馈。要确保您的提
这似乎应该有一个直截了当的答案,但在Google上花了很多时间,所以我找不到它。这可能是缺少正确关键字的情况。在我的RoR应用程序中,我有几个模型共享一种特定类型的字符串属性,该属性具有特殊验证和其他功能。我能想到的最接近的类似示例是表示URL的字符串。这会导致模型中出现大量重复(甚至单元测试中会出现更多重复),但我不确定如何让它更DRY。我能想到几个可能的方向...按照“validates_url_format_of”插件,但这只会让验证干给这个特殊的字符串它自己的模型,但这看起来很像重溶液为这个特殊的字符串创建一个ruby类,但是我如何得到ActiveRecord关联这个类模型
假设我做了一个模块如下:m=Module.newdoclassCendend三个问题:除了对m的引用之外,还有什么方法可以访问C和m中的其他内容?我可以在创建匿名模块后为其命名吗(就像我输入“module...”一样)?如何在使用完匿名模块后将其删除,使其定义的常量不再存在? 最佳答案 三个答案:是的,使用ObjectSpace.此代码使c引用你的类(class)C不引用m:c=nilObjectSpace.each_object{|obj|c=objif(Class===objandobj.name=~/::C$/)}当然这取决于
我试图在一个项目中使用rake,如果我把所有东西都放到Rakefile中,它会很大并且很难读取/找到东西,所以我试着将每个命名空间放在lib/rake中它自己的文件中,我添加了这个到我的rake文件的顶部:Dir['#{File.dirname(__FILE__)}/lib/rake/*.rake'].map{|f|requiref}它加载文件没问题,但没有任务。我现在只有一个.rake文件作为测试,名为“servers.rake”,它看起来像这样:namespace:serverdotask:testdoputs"test"endend所以当我运行rakeserver:testid时
出于纯粹的兴趣,我很好奇如何按顺序创建PI,而不是在过程结果之后生成数字,而是让数字在过程本身生成时显示。如果是这种情况,那么数字可以自行产生,我可以对以前看到的数字实现垃圾收集,从而创建一个无限系列。结果只是在Pi系列之后每秒生成一个数字。这是我通过互联网筛选的结果:这是流行的计算机友好算法,类机器算法:defarccot(x,unity)xpow=unity/xn=1sign=1sum=0loopdoterm=xpow/nbreakifterm==0sum+=sign*(xpow/n)xpow/=x*xn+=2sign=-signendsumenddefcalc_pi(digits