作者:觉悟 | 来源:互联网 | 2023-09-17 10:38
众所周之,服务器的设计永远不能依赖于单进程/单线程,由于PHP本质上是不支持多线程的,所以在开发过程中,只能把不同的逻辑或者用户分发到不同的进程之间进行处理(这是由系统自己调用分发的)。由此可知道在游戏中用户之间必须共享一些特定的公共数据,由于PHP进程之间不能够直接调用数据,所以就需要一个共公的数据库或者内存空间进行保存,因我的服务器采用的是WorkerMan进行开发的,所以用到的公共组件可以是GlobalData或者Redis组件,它是实质就是公有数据库服务。此处采用的是GlobalData组件。以下是实现代码:
class Events
{private static $globalClient;/*** WORKER端启动的时候调用,用于初始化全局数据* @param $worker*/public static function onWorkerStart($worker){//连接进程共享数据服务器self::$globalClient = new GlobalData\Client("127.0.0.1:2207");//创建当前服务器$server = new GameServer();//保存共享数据,本函数只执行一次self::$globalClient->add('server', $server);}/*** 当客户端连接时触发* 如果业务不需此回调可以删除onConnect* * @param int $client_id 连接id*/public static function onConnect($client_id){//检查是否有更新,返回更新结果//echo $client_id."\n";echo "connect:".Gateway::getAllClientCount()."\n";}/*** 当客户端发来消息时触发* @param int $client_id 连接id* @param mixed $message 具体消息*/public static function onMessage($client_id, $message){do{//获取服务器,当前服务器和保存的服务器环境$server = self::$globalClient->server;$oldServer = self::$globalClient->server;//开始处理客户端请求,内部调用响应函数返回客户端$t=$server->processClientRequest($client_id, $message);}while(!self::$globalClient->cas('server', $oldServer, $server));if($t){for($i=0;$iprocessServerResponse($t[$i][0],$t[$i][1],$t[$i][2],$t[$i][3],$t[$i][4]);}}}/*** 当用户断开连接时触发* @param int $client_id 连接id*/public static function onClose($client_id){echo "exit!\n";//当用户断开连接时//获取服务器,当前服务器和保存的服务器环境do{//获取服务器,当前服务器和保存的服务器环境$server = self::$globalClient->server;$oldServer = self::$globalClient->server;$server->disconnect($client_id);}while(!self::$globalClient->cas('server', $oldServer, $server));}
}
此处就是创建了一个GlobalData数据服务,里面存储的是游戏中公用的数据,封装在GameServer里面,每次都可通过GameServer进行调用。需要注意的就是因此方法的本质是IO阻塞式的,是一个原子操作,会影响到服务器的一定性能,在游戏中如果要达到正常通信,进行游戏分区是不很不错的方法的。
官方文档地址:http://doc.workerman.net/315189