flower_svr/class/gzhq_swoole.class.php
2021-06-11 16:09:56 +08:00

492 lines
17 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?php
/**
* Created by gzhq.
* User: 252378189@qq.com
* Date: 2017/12/28
* Time: 20:49
*/
//自动加载类
function __autoload($class){
//判断两个要执行的内容是否正常
if (!preg_match("/^[a-zA-Z0-9_]+$/", $class)) {
echo("要执行的方法里只能包含字母、数字、下画线\r\n");
return false;
}
if(file_exists(WEBPATH_DIR.'class'.DS.$class.'.class.php')){
require_once(WEBPATH_DIR.'class'.DS.$class.'.class.php');
if (!class_exists($class, false)) {
echo("找不到对应的类: $class ".__LINE__);
}
}else{
echo("找不到对应的文件: $class ".__LINE__);
}
}
class gzhq_swoole{
public $server=false;
public $is_debug = true;//是否打开调试
public $mysql_pool = false;//mysql 连接池
public $redis_pool = false;//redis 连接池
public function __construct($host = WEBSOCKET_SERVER_HOST, $port = WEBSOCKET_SERVER_PORT)
{
//$this->server = new swoole_websocket_server($host, $port,SWOOLE_PROCESS,SWOOLE_SOCK_TCP | SWOOLE_SSL);
$this->server = new swoole_websocket_server($host, $port);
$this->server->set([
// 输出限制
"buffer_output_size" => 1024 * 1024 * 1024,
"max_connection" => 10240,
"pipe_buffer_size" => 1024 * 1024 * 1024,
"log_file" => WEBPATH_DIR.'cache/swoole.log',
//'ssl_cert_file' => '/data/https/game.websocket/1_game.gamephp.com_bundle.crt',
//'ssl_key_file' => '/data/https/game.websocket/2_game.gamephp.com.key',
'open_tcp_nodelay' => 1,
'open_cpu_affinity' => 1,
'task_worker_num' =>8,
'dispatch_mode'=>2,
'daemonize' => 0,//守护进程化。设置daemonize => 1时程序将转入后台作为守护进程运行。长时间运行的服务器端程序必须启用此项。
'reactor_num' => 2,//2个处理线程的数量
'worker_num' => 4,//4个线程
'max_request' => 0,//最大10万个连接请求
'heartbeat_idle_time' => 50,//如果客户端超过600秒未向服务器发消息
'heartbeat_check_interval' =>55//每60秒检查一次所有的连接
]);
}
public function start(){
$this->_echo_log(__CLASS__."->".__FUNCTION__);
$this->server->on('start', [$this, 'onStart']);
$this->server->on('shutdown', [$this, 'onShutdown']);
$this->server->on('workerStart', [$this, 'onWorkerStart']);
$this->server->on('workerStop', [$this, 'onWorkerStop']);
$this->server->on('workerError', [$this, 'onWorkerError']);
$this->server->on('connect', [$this, 'onConnect']);
$this->server->on('request', [$this, 'onRequest']);
$this->server->on('open', [$this, 'onOpen']);
$this->server->on('message', [$this, 'onMessage']);
$this->server->on('task', [$this, 'onTask']);
$this->server->on('finish', [$this, 'onFinish']);
$this->server->on('close', [$this, 'onClose']);
$this->server->start();
}
public function onOpen($server, $request) {
$this->_echo_log(__CLASS__."->".__FUNCTION__);
$this->_echo_log("1连接参数为");
if(isset($request->get) && !empty($request->get)){
$tmp_arr = $request->get;
//检查是否有关键数据
if(is_array($tmp_arr) && isset($tmp_arr['token'])){
$tmp_arr['token'] = urldecode($tmp_arr['token']);
$tmp_arr['fd'] = $request->fd;
$tmp_arr['ip'] = $request->server['remote_addr'];
//如果数据正确,则记录连接成功的在线用户
if($this->_user_open($tmp_arr)){
$this->_echo_log("用户连接成功:".$tmp_arr['fd']."|".$tmp_arr['ip']);
$data = array();
$data['fd'] = $tmp_arr['fd'];
$data['ip'] = $tmp_arr['ip'];
$data['a'] = "open";
$data['m'] = "user_login";
$data['d'] = array("code"=>'1',"msg"=>"连接成功!");
$this->server->task($data);
return true;
}else{//如果数据不正确,则不能连接
$this->_echo_log("用户连接失败了:".$tmp_arr['token']);
$this->server->close($request->fd);
}
}else{//如果数据不正确则不能连接
$this->_echo_log("key数据不正确:",$tmp_arr);
$this->server->close($request->fd);
}
}else{
$this->_echo_log("get数据不正确:\r\n");
$this->server->close($request->fd);
}
return true;
}
public function onMessage($server, $frame) {
$this->_echo_log(__CLASS__."->".__FUNCTION__."\r\n");
$this->_echo_log("\r\n<br> 上传的数据:".$frame->data." \r\n<br>");
$data = json_decode($frame->data,true);
//如果有合法的参数,则执行请求的操作
if(!empty($data) && isset($data["a"]) && isset($data["m"]) && isset($data["d"]) ) {
//判断两个要执行的内容是否正常
if (!preg_match("/^[a-zA-Z0-9_]+$/", $data["a"]) || !preg_match("/^[a-zA-Z0-9_]+$/", $data["m"])) {
$this->_echo_log("要执行的方法里只能包含字母、数字、下画线\r\n");
return false;
}
//判断是否有这个类
if (!class_exists($data['m'])) {
$this->_echo_log(__FILE__ . "找不到对应的类: " . $data['m'] . ":" . __LINE__);
return false;
}
$data['fd'] = $frame->fd;
$data['ip'] = $this->server->connections[$frame->fd]['remote_ip'];
$tmp_task_id = $this->server->task($data);
$this->_echo_log("进行task任务:".$tmp_task_id);
}else{
$this->_echo_log($frame->data);
$this->server->send_user($frame->fd,$data);
}
return true;
}
public function onClose($server, $fd) {
$this->_echo_log(__CLASS__."->".__FUNCTION__."\r\n");
$this->_echo_log("client fd:{$fd} closed\r\n");
if($GLOBALS['USER_LIST_FD']->exist($fd)){
$uid = $GLOBALS['USER_LIST_FD']->get($fd);
if(!empty($uid['uid'])){
$this->_user_close($uid['uid']);
}
$GLOBALS['USER_LIST_FD']->del($fd);
$GLOBALS['USER_LIST']->del($uid['uid']);
}
return true;
}
public function onRequest($request,$response){
$this->_echo_log(__CLASS__."->".__FUNCTION__."\r\n");
$a = $request->post['a'];
$m = $request->post['m'];
$this->_echo_log($a."=>".$m."\r\n");
if ($a == 'login') {
$response->end("true");
return true;
}
if(empty($request->post['token']) || empty($request->server['remote_addr'])){
$this->_echo_log("数据格式不正确");
$response->end("false");
return false;
}
$token = urldecode($request->post['token']);
$ip = $request->server['remote_addr'];
$act = new ajax_user_msg();
$tmp_data = $act->check_right($token,$ip);
if($tmp_data){//检查数据格式以及数据是否正确
//判断两个要执行的内容是否正常
if (
!preg_match("/^[a-zA-Z0-9_]+$/", $tmp_data["a"])
|| !preg_match("/^[a-zA-Z0-9_]+$/", $tmp_data["m"])
|| !preg_match("/^[a-zA-Z0-9_]+$/", $tmp_data["do_a"])
|| !isset($tmp_data["uid"])
|| !isset($tmp_data["do_a"])
) {
$this->_echo_log("要执行的方法里只能包含字母、数字、下画线\r\n",$tmp_data);
$response->end("false");
}else{
$tmp_data['ip'] = $ip;
$tmp_return = $act->{$tmp_data['do_a']}($this,$tmp_data);
if(is_array($tmp_return)){
$tmp_return = return_ajax($tmp_return);
}
$response->end($tmp_return);
}
}else{
$this->_echo_log($ip."|数据不正确|:".$token);
$response->end("false");
}
}
public function onConnect($server, $fd){
$this->_echo_log(__CLASS__."->".__FUNCTION__."\r\n");
}
public function onStart($server){
$this->_echo_log(__CLASS__."->".__FUNCTION__."\r\n");
}
public function onShutdown($server){
$this->_echo_log(__CLASS__."->".__FUNCTION__."\r\n");
}
public function onWorkerStart($server, $workerId){
$this->_echo_log(__CLASS__."->".__FUNCTION__."\r\n");
//在第一个工作进程时启动定时器,每秒执行一次
if($workerId==0){
/*
$tmp_redis = new myredis();
swoole_timer_tick(1000,function() use($tmp_redis) {
while($mydata = get_reids_push($tmp_redis,SYS_INFO_LIST)){
if($mydata){//从队列里拿消息数据出来发送
$tmp_fd = $this->get_user_by_uid($mydata['uid']);
if(!empty($tmp_fd)){//如果是在当前服务器
$mydata['fd'] =$tmp_fd['fd'];
$mydata['ip'] ='127.0.0.1';
$this->server->task($mydata);
}else{//如果不是在当前服务器,则把数据放回去
set_reids_push($tmp_redis,USER_INFO_LIST,$mydata);
}
}else{
break;
}
}
});
*/
}
}
public function onWorkerStop($server, $workerId){
$this->_echo_log(__CLASS__."->".__FUNCTION__."\r\n");
}
public function onWorkerError($server, $workerId, $workerPid, $exitCode, $sigNo){
$this->_echo_log(__CLASS__."->".__FUNCTION__."\r\n");
}
public function onTask($server,$task_Id, $from_Id, $data){
$this->_echo_log(__CLASS__."->".__FUNCTION__."\r\n");
$data['server'] = $this;
$act = new $data['m']();
//是否有这个方法在
if (!method_exists($act, $data['a'])) {
$this->_echo_log(__FILE__ . "|" . $data['m'] . "找不到对应的方法: " . $data['a'] . ":" . __LINE__);
unset($data,$act);
$this->server->finish($task_Id);
return false;
}
if($act->set_data($data)){
$this->_echo_log("执行情况:".$act->{$data['a']}() );
$this->server->finish($task_Id);
return true;
}else{
$this->_echo_log("执行出错:".$data['m']."->".$data['a']."\r\n");
$this->server->finish($task_Id);
return false;
}
}
public function onFinish($server, $data){
$this->_echo_log(__CLASS__."->".__FUNCTION__."\r\n");
}
//根据用户ID查用户的连接记录
public function get_user_by_uid($uid){
$this->_echo_log(__CLASS__."->".__FUNCTION__."\r\n");
if($GLOBALS['USER_LIST']->exist($uid)){
$tmp_val = $GLOBALS['USER_LIST']->get($uid);
return $tmp_val;
}else{
return false;
}
}
//根据用户的fd查用户的uid
public function get_user_by_fd($fd){
$this->_echo_log(__CLASS__."->".__FUNCTION__."\r\n");
if($GLOBALS['USER_LIST_FD']->exist($fd)){
$tmp_val = $GLOBALS['USER_LIST_FD']->get($fd);
return $tmp_val;
}else{
return false;
}
}
//设置用户在线
/*
$data = array(
"fd" => ,//"连接",
"uid" => ,//用户ID,
);
*/
public function set_user_list($data){
//删掉这个uid之前绑定的连接
$tmp_uid = $GLOBALS['USER_LIST']->get($data['uid']);
if($tmp_uid && $tmp_uid['fd']>0){
$GLOBALS['USER_LIST_FD']->del($tmp_uid['fd']);
$GLOBALS['USER_LIST']->del($data['uid']);
}
$GLOBALS['USER_LIST']->set($data['uid'],array('fd'=>$data['fd']));
$GLOBALS['USER_LIST_FD']->set($data['fd'],array('uid'=>$data['uid']));
return true;
}
//给某个用户发信息
public function send_user($fd,$data,$opcode=1,$finish=true){
$this->_echo_log(__CLASS__."->".__FUNCTION__."\r\n");
if(empty($fd)){
return false;
}
if(is_array($data)){
$data = return_ajax($data);
}
//检测通道是否存在
if(!$this->server->exist($fd)){
$this->_echo_log("通道[ $fd ]的客户端已经断开,无法发送消息!\r\n",$data);
unset($data);
return false;
}else{
$this->server->push($fd,$data,$opcode,$finish);
unset($data);
return $finish;
}
}
//给指定用户发信息
public function send_all($arr,$data,$opcode=1,$finish=true){
$this->_echo_log(__CLASS__."->".__FUNCTION__."\r\n");
if(!empty($arr)){
foreach($arr as $uid){
if($GLOBALS['USER_LIST']->exist($uid)){
$tmp_fd = $GLOBALS['USER_LIST']->get($uid);
if($this->send_user($tmp_fd['fd'],$data,$opcode,$finish)){
$this->_echo_log('用户['. $uid .']发送消息成功!\r\n');
}else{
$this->_echo_log('用户['. $uid .']的客户端已经断开,无法发送消息!\r\n');
}
}
}
}else{
$this->_echo_log('没有指定要发信息的用户,无法发送消息!\r\n');
}
return true;
}
//处理用户登入来的问题
/*
$arr = array(
"fd" =>'',//用户websocket连接
"token"=>'',//登陆token
"ip"=>'',//客户端IP
);
*/
private function _user_open($arr){
if(empty($arr) || !isset($arr['token']) || $arr['token']==''){
$this->_echo_log('_user_open:消息不正确!\r\n');
return false;
}
$tmp_token = get_login_token($arr['token']);
if(!empty($tmp_token) && isset($tmp_token['uid'])){
$data = array(
"uid"=>$tmp_token['uid'],
"fd"=>$arr['fd']
);
$this->set_user_list($data);
return true;
}else{
$this->_echo_log($tmp_token,$arr['token']."====>2");
return false;
}
}
//根据玩家uid通知同房间的对手玩家掉线了游戏结束
private function _user_close($uid){
$this->_echo_log(__CLASS__."->".__FUNCTION__."\r\n");
return true;
}
//打开调试
/*
* $data=>要求输出的内容,
* $data2=>要求输出的内容2
*/
public function _echo_log($data,$data2=''){
//如果打开了调试
if($this->is_debug==true) {
if(is_array($data) || is_object($data)) {
var_dump($data);
} else {
echo(date('Y-m-d H:i:s')." | ".$data);
}
echo("\r\n");
if (!empty($data2)) {
if(is_array($data2) || is_object($data2)) {
var_dump($data2);
} else {
echo($data2);
}
echo("\r\n");
}
}
}
}
//redis连接池
class RedisPool{
protected $pool;
function __construct(){
$this->pool = new SplQueue;
}
function put($redis){
$this->pool->push($redis);
}
function get(){
//有空闲连接
if (count($this->pool) > 0){
return $this->pool->pop();
}
//无空闲连接,创建新连接
$redis = new myredis();
if ($redis == false) {
return false;
} else {
return $redis;
}
}
}
//Mysql连接池
class MysqlPool{
protected $pool;
function __construct(){
$this->pool = new SplQueue;
}
function put($conn){
$this->pool->push($conn);
}
function get(){
//有空闲连接
if (count($this->pool) > 0){
$conn = $this->pool->pop();
if($conn->myping()){
return $conn;
}else{
$conn->Close();
}
}
//无空闲连接,创建新连接
$conn = new DB_ZDE();
if ($conn == false) {
return false;
} else {
return $conn;
}
}
}