PHP游戏服务器,多个TCP客户端?

10

我正在制作一个基于Web的多人游戏。考虑到实时性,我确定Websockets是处理通信的最佳方式。客户端使用HTML5画布来渲染游戏,并使用Websockets与主机进行通信。

我选择使用PHP来托管游戏,因为它似乎是托管提供商首选的语言。我之前没有使用过PHP,但在Java中使用了类似Websockets的东西,但非常依赖于多线程。

我已经看过一些关于PHP sockets和多个客户端的教程;但其中大多数做法是为每个客户端fork出新进程。由于我将有一个不断运行的游戏循环,因此我认为这并不适合。

我想要实现的是为每个连接的客户端分配端口,监听新客户端,与当前客户端列表交换数据,并同时运行游戏循环的方法。

我需要帮助的地方如下:

  • 如何找到并分配端口给新客户端,通知客户端该端口,并在他们断开连接时清理端口。
  • 如何在不阻塞游戏循环的情况下执行上述所有socket事务。接受来自客户端的部分消息并仅对完整消息进行操作是可接受的。

有人能给我一些关于如何实现这些目标的技术建议吗?我认为这不是对PHP的过高要求,但如果我错了,请指出!

以下是我希望服务器端实现的伪代码。没有任何函数应该受阻:

Array clients;

while(gamerunning)
{
    CheckForNewClients();
    GetStatusFromClients();
    DoGameUpdate();
    SendGameStateToClients();
}

[更新] 对于任何感兴趣的人,我创建了一个专门支持WebSockets(特别是使用Java和'TooTallNates' WebSocket库)的应用程序,而不是实际的Web服务,因为这似乎更有意义,尽管恰好由于安全问题,大多数Web浏览器已经放弃了WebSockets。


1
如果你能获得一个允许你在上面运行Node.js的VPS或类似物,我强烈建议选择Node路径。在Node.js中创建多人游戏服务器非常简单。 - Ivo Wetzel
不,Node.js简而言之是用于编写服务器的闪电般快速、事件驱动、服务器端JavaScript。 - nocksock
1
PHP并不是最优的解决方案,你需要一种基于事件的语言(如nodejs),或者具有事件框架的语言(如ruby - eventmachine、python - twisted、tornado等)。长时间运行的PHP脚本会带来痛苦和泪水(这里有经验之声..) - James Butler
我记得PHP不支持多线程,你可能需要选择其他语言。 - Danil Chernokalov
我正在使用PHP WebSockets作为实时游戏服务器:https://github.com/Devristo/phpws - psycho brm
显示剩余2条评论
2个回答

7
你需要运行一个PHP守护进程才能有效地完成这个任务(必须使用PHP 5.3)。我写了一篇关于如何使用PHP实现守护进程的全面概述,链接在此:PHP for daemon processes。无论你选择什么,我建议你使用基于事件的运行循环系统。
我设计了一个基本的RunLoop库叫做LooPHP,如果你要处理*_select,它可能会非常有用。如果你有任何问题,我很乐意回答。
编辑:
在基于事件的系统中,你不是简单地while一个命令列表,而是对监听器做出反应。例如...
与其这样做:
while( 1 ) {
    ... /* listen, react */
} /* repeat */

运行循环通过注册监听器(套接字和其他异步事件生成器)来工作。

class ReactClass { ... }

$loop = new LooPHP_EventLoop( new ReactClass );

//add one time event
$loop->addEvent( function() {
    print "This event was called 0.5 second after being added\n";
}, 0.5 /* in seconds */ );

//this creates a repeating event, this is called right away and repeats
$add_event = function() use ( $loop, &$add_event ) {
    print "This event is REPEATEDLY called 0.1 every second\n";
    $loop->addEvent( $add_event, 0.1 );
};
$add_event();

//start the loop processing, no events are processed until this is done
$loop->run(); //php doesn't leave this call until the daemon is done
exit(0); //cleanly exit

上述案例是一个非常简单的1源EventLoop和手动添加定时函数(这些甚至可以在调用ReactClass时添加)。
在我工作的应用程序中,我需要将异步事件馈送到后端(通过套接字),然后需要能够从原始事件任意偏移调用函数(针对超时客户端等)。
如果您想要更多示例,您可以在github上找到它们。
希望您会发现这个有用。

我喜欢这个的外观。你能向我展示如何设置,以便事件函数可以访问在单独的游戏循环中不断更新的对象数组吗? - Toby Wilson
这个库能否作为游戏服务器使用,让网页游戏每秒连接三次以更新其状态? - psycho brm
@psychobrm 这取决于你的负载、大小和成本。我建议你试一试,看它是否能够很好地扩展。 - Kendall Hopkins

6
我不建议在这种类型的应用程序中使用PHP。PHP官方不支持多线程,并且运行PHP脚本一段未定义的时间(如服务器)并不是一个被广告的功能。
当然,你可以尝试创造历史 :) (如果我错了,请纠正我)

3
也许我已经创造了历史……过去我曾使用PHP编写socket服务器守护进程(因为我的雇主强制使用该技术),但我并不认为存在任何问题。无论是单进程还是多进程,都能够完美地工作。 - netcoder
1
我也是,我目前正在用PHP编写游戏后端(作为守护程序)。它通过XMPP网关监听/写入消息。到目前为止,它工作得非常好(不是超级快,但无法击败PHP易用性)。 - Kendall Hopkins
1
@Kendall:我认为速度不是一个问题。我也用Java编写过套接字守护程序,但PHP在速度方面击败了它们中的大多数。首先,没有JVM需要启动。其次,与Java的抽象套接字层不同,PHP非常接近C原始套接字。 - netcoder
有人建议将游戏状态存储在SQL数据库中,但我不认为这会起作用,因为游戏事件会在服务器端发生,并且可能会产生大量的CPU开销。 - Toby Wilson
完全同意netcoder的观点,特别是现在PHP在任何技术上都能击败WebSockets,例如Java,因为它现在有OPCache预编译字节码,没有JVM或其他糟糕的过度工程灰尘,而且由于标量类型,PHP7甚至比预先OPCache集成更快,以备不时之需。我为WebSocket服务器/客户端编写了自己的库,因为两者都不够 - https://github.com/arthurkushman/php-wssc。这只是1.2.5版本,可能不完全适合生产环境,但运行良好。还有其他像Ratchet等的库。 - Arthur Kushman
显示剩余3条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接