workerman 业务并发测试

<?php
use \Workerman\Worker;
use \Workerman\WebServer;
use \GatewayWorker\Gateway;
use \GatewayWorker\BusinessWorker;
use \Workerman\Autoloader;
use \Workerman\Connection\AsyncTcpConnection;
use \Workerman\Lib\Timer;

require_once './vendor/autoload.php';
$worker = new Worker ();
$worker->onWorkerStart = 'connect';
function connect() {
	// 2000个链接
	// if ($count ++ >= 400) {
	// return;
	// }
	for($count = 0; $count < 400; $count ++) {
		$func = function ($count) {
			$session_id = 'd34pkfuf88vom9ugptop7e5' . $count;
			// 建立异步链接
			// $con = new AsyncTcpConnection ( 'ws://xxxx:8282' );
			$con = new AsyncTcpConnection ( 'ws://xxxxx:8282' );
			$con->onMessage = function ($con, $msg) use ($session_id, $count) {
				// 服务器消息推送
				echo "recv $session_id $msg\n";
				$msg = json_decode ( $msg, true );
				if ($msg && isset ( $msg ['action'] )) {
					switch ($msg ['action']) {
						case 'broadcast' :
							$time = ( int ) date ( 'dHis', time () );
							$con->send ( "{\"model\":\"__workerman\",\"action\":\"set_value\",\"value_key\":\"client_time\",\"value_value\":{$time}}" );
							break;
					}
				}
			};
			$con->onClose = function ($con) use ($session_id, $count) {
				echo "con $session_id close\n";
			};
			$con->onConnect = function ($con) use ($session_id, $count) {
				// $con->send ( "{\"model\":\"__workerman\",\"action\":\"set_value\",\"value_key\":\"score\",\"value_value\":{$val}}" );
				// 模拟登录动作
				$con->send ( "{\"model\":\"remote\",\"action\":\"msg\",\"remote_url\":\"http://xxxxxx/workerman_remote/do/\",\"params\":{\"model\":\"user\",\"action\":\"login\",\"rm_session_id\":\"{$session_id}\"}}" );
				// 当前链接每10秒发个心跳包
				$time = ( int ) date ( 'dHis', time () );
				$con->send ( "{\"model\":\"__workerman\",\"action\":\"set_value\",\"value_key\":\"client_time\",\"value_value\":{$time}}" );
				Timer::add ( 10, function () use ($con, $session_id, $count, $time) {
					// 每10秒推送一个消息
					// $con->send ( "{\"model\":\"user\",\"action\":\"sys_time\",\"session_id\":\"{$session_id}\",\"client_time\":\"{$time}\"}" );
					// 模拟数钱,一秒推送10个消息
					for($i = 0; $i < 10; $i ++) {
						$val = ( int ) date ( 'dHis', time () );
						$con->send ( "{\"model\":\"__workerman\",\"action\":\"set_value\",\"value_key\":\"score\",\"value_value\":{$val}}" );
					}
					echo $count . " send complete\n";
				} );
			};
			$con->connect ();
			echo $count . " connections complete\n";
		};
		$func ( $count );
	}
}
Worker::runAll ();

1

2

在400条的情况下,内存用不了多少,稳定性也有保证,不过实际情况,还是得具体场景才能判断.

workerman+yii实现快速开发交互

示例:

http://24.igd.cc/workerman/page?caihaibin=ok

外部使用demo

http://24.igd.cc/workerman_remote/page?caihaibin=ok

http://gxu.igd.cn/workerman_remote/page?caihaibin=ok

(端口只有一个, 多个项目使用同一个workerman,通过特殊机制,实现将workerman请求转发到yii,并共享两边的sessiono数据,支持wss)

需要明确一个关键点,workerman本身是一个独立的运行容器,类似 apache+php的概念,独立运行.

http://24.igd.cc/workerman_remote/page?caihaibin=ok

因为 workerman 是一个独立的脚本容器,所以这类代码

lib ( ‘workerman/Gateway.php’ );
\GatewayClient\Gateway::joinGroup ( State ( ‘client_id’ ), WebSocketTools::KEY_PRE . ‘test’ );

其实比较像调用workerman的接口,实现相关功能.需要理解这块,所以两者有一定的时间差,这块初试化时,必须认login推送返回的消息为准,做为完全建立两者通讯的标志.如果没有,页面应当进行刷新,再次进行连接.有时websocket open是成功的,但是login消息也会没有推送回来,表示之前的网络通讯出了问题.当做不成功.

 

workerman 游戏的两种模式

第一种:

一种频率不高的,几秒甚至十几秒点一次的,如猜拳,24点小游戏.直接使用post调用yii动作实现游戏逻辑.

第二种:

频率非常高的,类似数钱,一秒会有数次请求的,全部走workerman session,不经过yii session 和数据库. 前台屏幕数据显示,可通过gatewayclient获取workerman所有的会话数据,再根据数据进行排名显示. 当比赛结束时,再将数据插入数据库.

//===============发送workerman 内部参数,用于直接调用workerman动作===============
// 自定义一个key 和 value ,一秒内多次推送也不影响性能
ws.send(JSON.stringify({model:’__workerman’,action:’set_value’,value_key:’score’,value_value:Math.random(0)}));
//===============发送workerman 内部参数,用于直接调用workerman动作

//gateway 获取session数据,不同项目,分组前缀必须不同,防止冲突

Gateway::getAllClientSessions ( WebSocketTools::KEY_PRE . ‘test’ )

广度workerman时序图