492 lines
17 KiB
PHP
492 lines
17 KiB
PHP
<?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;
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
|