php websocket udp,swoole创建websocket服务并且支持https服务,同时监听tcp,udp端口

namespace serve\websocket;

// use serve\websocket\task\Message as taskMessage;

use serve\websocket\common\Fast;

use sok\App;

// use sok\utils\Arr;

// use Swoole\Timer;

use Swoole\WebSocket\Server;

$GLOBALS['client'] = []; //存储用户信息 key=用户的fd

// $MakeId=new MakeId;

// [ 应用入口文件 ]

class Chat {

use Fast;

// public $MakeId;

public $server; //当前socket服务对象

public $websocketConfig = [

// 本机服务配置

'ip' => '0.0.0.0', // 监听地址

'port' => 9501, // 监听端口

'secret_key' => '123456', //允许推送消息的秘钥

'mode' => "SWOOLE_PROCESS", // 运行模式 默认为SWOOLE_PROCESS

'sock_type' => ["SWOOLE_SOCK_TCP", "SWOOLE_SSL"], //数组 sock type 默认为SWOOLE_SOCK_TCP | SWOOLE_SSL

'isInsertMysql' => true, //发送消息后是否写入到mysql数据库

// 分布式服务器通道 //允许哪些ip +秘钥连接到与本机接收推送消息

"distributed" => [

'local' => [

// 本机配置

"host" => '27.1.0.1', //公网ip

"ip" => '192.168.0.150', //本机ip局域组网,分布式接口ip

"secret_key" => "123456",

"port" => 9501,

],

// 搭档服务器配置

"websocket_group" => [

[

"ip" => "192.168.0.150", //ip组网,分布式连接ip

"secret_key" => "123456", //组网,分布式连接秘钥

"port" => 9502, //服务端开启服务的端口号

], [

"ip" => "192.168.0.150",

"secret_key" => "123456",

"port" => 9502, //

],

],

],

'set' => [

'dispatch_mode' => 2, //绑定uid=5

'daemonize' => false, //守护进程化。

'heartbeat_check_interval' => 10, //间隔多少秒进行心跳检测

'heartbeat_idle_time' => 60, //间隔多少秒无状态 踢下线

'worker_num' => 1, //开启进程数量

'insert_db_turns_time' => 5, //轮流读取redis缓存写入数据库。间隔秒,一般对数据库实时要求并不高,时间可以设置在5-10秒,读取redis缓存消息堆,批量写入数据库,减少数据库操作频率。提升写入性能

'insert_db_number' => 1000, //间隔秒,读取redis缓存消息堆数量,批量写入数据库,如果单台redis主机建议每秒吞吐量2000以内。

],

];

// 自动注册属性 防止连接丢失

public function __get($name) {

switch ($name) {

// case 'Arr':

// // 连接Arr工具类

// return $this->$name = new Arr;

// break;

default:

# code...

break;

}

}

public function __set($name, $vue) {

$this->$name = $vue;

}

public function __construct($config = []) {

if (!empty($config) && is_array($config)) {

$websocketConfig = array_merge($this->websocketConfig, $config);

} else {

$websocketConfig = array_merge($this->websocketConfig, App::config('websocket'));

}

$isSsl = false;

if (isset($websocketConfig['set']['ssl_cert_file']) && isset($websocketConfig['set']['ssl_key_file']) && !empty($websocketConfig['set']['ssl_cert_file'])) {

$websocketConfig['set']['ssl_cert_file'] = App::getRootPath() . '/ssl/' . $websocketConfig['set']['ssl_cert_file'];

$websocketConfig['set']['ssl_key_file'] = App::getRootPath() . '/ssl/' . $websocketConfig['set']['ssl_key_file'];

$isSsl = true;

}

echo "serve\websocket\chat.php isSsl:$isSsl:\n";

// ws服务

// print_r($websocketConfig);

if (isset($websocketConfig['sock_type'][1]) && $isSsl) {

$server = new Server($websocketConfig['ip'], $websocketConfig['port'], constant($websocketConfig['mode']), constant($websocketConfig['sock_type'][0]) | constant($websocketConfig['sock_type'][1]));

echo "开启wss服务\n";

} else {

$server = new Server($websocketConfig['ip'], $websocketConfig['port'], constant($websocketConfig['mode']), constant($websocketConfig['sock_type'][0]));

}

// $this->distributed = $this->websocketConfig['distributed'];

$local = $websocketConfig['distributed']['local']; //本机ip配置

$websocket_group = $websocketConfig['distributed']['websocket_group'] ?? null; //联机ip配置

// $websocketConfig['set']['dispatch_func'] = function ($serv, $fd, $type, $data) use ($websocket_group) {

// // echo $worker_num = $serv->setting['worker_num'] . "\n";

// // $type数据的类型,0表示来自客户端的数据发送,4表示客户端连接关闭,5表示客户端连接建立

// if ($worker_num > 1 && !empty($websocket_group)) {

// $clientInfo = $serv->getClientInfo($fd);

// // $clientInfo['remote_ip'];

// foreach ($websocket_group as $key => $value) {

// if ($value['ip'] === $clientInfo['remote_ip']) {

// return 0;

// }

// }

// $worker = ($fd % ($worker_num - 1)) + 1;

// return $worker;

// } else {

// return 0;

// }

// return intval($data[0]);

// };

// $this->websocketConfig = $websocketConfig;

// $websocketConfig['set']['config'] = $this->websocketConfig;

$server->websocketConfig = $websocketConfig;

// print_r($websocket_group);

// return;

//配置参数

$server->set($websocketConfig['set']);

// $onManagerStart = new \serve\websocket\managerstart\Message($server); //onMeanagerStert 绑定

// 当管理进程启动时调用它

$server->on('ManagerStart', [$this, 'onManagerStart']);

// $server->on('ManagerStart', [$onManagerStart, 'onManagerStart']);

// $server->set(array("open_websocket_close_frame" => true));

//启动每个worker进程会触发

$server->on('WorkerStart', [$this, 'onWorkerStart']);

//建立连接触发

// $server->on('open', [$this, 'onOpen']);

$onOpen = new \serve\websocket\open\Message($server); //onOpen 绑定类

$onMessage = new \serve\websocket\message\Message($server); //onMessage绑定

// $message->config = $websocketConfig;

$onTask = new \serve\websocket\task\Message($server); //onTask绑定

//接收到消息

// $server->on('message', [$message, 'onMessage']);

// $server->on('task', [$this, 'onTask']); //接收到消息

// $server->on('finish', [$this, 'onFinish']); //接收到消息

// $server->on('receive', [$this, 'onReceive']); //接收到消息

//关闭连接触发

$server->on('close', [$this, 'onClose']);

//创建Server对象,监听 127.0.0.1:9502端口,类型为SWOOLE_SOCK_UDP

$udp_server = $server->listen('192.168.0.150', 9502, SWOOLE_SOCK_UDP);

// udp服务器组

$udpsocket_group = $websocketConfig['distributed']['udpsocket_group'] ?? null;

//监听数据接收事件

$udp_server->on('packet', function ($serv, $data, $clientInfo) use ($server, $udpsocket_group) {

// print_r();

$isAuth = false;

if ($clientInfo['address'] === '127.0.0.1') {

$isAuth = true;

} else {

$data = json_decode($data, true);

foreach ($udpsocket_group as $key => $value) {

if ($value['ip'] === $clientInfo['address'] && $value['secret_key'] === $data['sk']) {

$isAuth = true;

break;

}

}

}

if ($isAuth === true) {

$data = [

'message' => 'ok',

'code' => 200,

'data' => $data,

];

} else {

$data = [

'message' => '失败',

'code' => 400,

'data' => $data,

];

}

$data = json_encode($data, JSON_UNESCAPED_UNICODE);

$serv->sendto($clientInfo['address'], $clientInfo['port'], "Server " . $data);

// var_dump($clientInfo);

});

//......设置各个回调......

//多监听一个tcp端口,对外开启tcp服务,并设置tcp服务器的回调

$tcp_server = $server->listen('0.0.0.0', 9503, SWOOLE_SOCK_TCP);

//需要调用 set 方法覆盖主服务器的设置

$tcp_server->set([

// "ssl_cert_file" => App::getRootPath() . '/ssl/' . $websocketConfig['set']['ssl_cert_file'],

// "ssl_key_file" => App::getRootPath() . '/ssl/' . $websocketConfig['set']['ssl_key_file'],

// 'open_mqtt_protocol' => true,

'open_http_protocol' => false, // 设置这个端口关闭http协议功能

]);

// $udp_server = $server->listen('0.0.0.0', 9502, SWOOLE_SOCK_UDP);

// //默认新监听的端口 9999 会继承主服务器的设置,也是 Http 协议

// //需要调用 set 方法覆盖主服务器的设置

// $udp_server->set([

// 'open_http_protocol' => false, // 设置这个端口关闭http协议功能

// ]);

// $udp_server->on("receive", function ($serv, $fd, $threadId, $data) use ($server) {

// print_r($data);

// // $serv->push($fd, $data);

// });

$tcp_server->on("message", function ($serv, $data) use ($server) {

echo "tcp_server";

echo $data;

// $serv->push($fd, $data);

});

$tcp_server->on('connect', function ($serv, $fd) {

echo "Client:Connect.\n";

$serv->send($fd, '{"fd":"' . $fd . '"}' . "\n");

});

$tcp_server->on('receive', function ($serv, $fd, $from_id, $data) {

$clientInfo = $serv->getClientInfo($fd);

// print_r($clientInfo);

$distributed = $this->websocketConfig['distributed'];

$source = $this->websocketConfig['source'];

$socket_group = $distributed['socket_group'];

// 验证ip+fd是否合法

if (isset($GLOBALS['client'][$fd]) && $GLOBALS['client'][$fd]['isServer'] == true) {

echo "验证通过$fd\n";

print_r($data);

$data = json_decode($data, true);

$serv->send($fd, json_encode($data, JSON_UNESCAPED_UNICODE) . "\n");

# code...

} else {

// 验证服务器是否合法

// if ($clientInfo['remote_ip'] == $addrIp) {

$data = json_decode($data, true);

// if (isset($data['sk']) && $data['sk'] == $sk) {

// $serv->$addrIp = $fd;

// 分布服务器认证授权

echo "\n组网服务器正则进行连接验证fd:{$fd} ip:{$clientInfo['remote_ip']} sk:{$data['sk']}\n";

// $distributed = $this->distributed;

// $websocket_group = $server->websocketConfig['websocket_group'];

if (isset($data['sk']) && !empty($socket_group) && is_array($socket_group)) {

$ip = $clientInfo['remote_ip']; //获取客户端ip

foreach ($socket_group as $key => $value) {

if ($value['ip'] === $ip && $value['secret_key'] === $data['sk']) {

echo "\n组网服务器已连接fd:{$fd} ip:{$ip} sk:{$data['sk']}\n";

// ip +密码验证通过 创建授权服务器的联网许可证明,保存到redis缓存服务器

// $fdinfo = $server->getClientInfo($request->fd);

// $ip = $fdinfo['remote_ip'];

$uid = intval(ip2long($distributed['local']['ip']) . $distributed['local']['port'] . ip2long($ip));

// print_r($this->distributed['local']);

$ClientInfo = [

'fd' => $fd,

// 'uid' => $uid,

"port" => $distributed['local']['port'],

'ip' => $distributed['local']['ip'],

"time" => time(),

];

$data['source'] = 'pc';

// $server->bind($request->fd, 12355464110647986);

// $fdinfo = $server->getClientInfo($request->fd);

$fdInfo = [

'uid' => $uid,

'isServer' => true,

"source" => $data['source'],

'time' => time(),

];

$GLOBALS['client'][$fd] = $fdInfo;

//uid缓存到本机缓存池, key=本机ip

$oldClient = $this->redis()->hGet("ws_clientInfo", $uid);

is_array($oldClient) or $oldClient = [];

$oldClient[$data['source']] = $ClientInfo;

$this->redis()->hSet("ws_clientInfo", $uid, $oldClient);

//———————————————————————————————验证通过 存入redis——fdInfo=hGet(ws_fdInfo.local->ip,fd)————clinetInfo= hGet(ws_clientInfo,uid)————————————————————————————————————

$returnMsg = [

'message' => '授权成功',

'code' => 200,

'data' => [],

];

// $server->push($fd, json_encode($returnMsg));

echo "验证通过$fd\n";

$serv->send($fd, json_encode($returnMsg, JSON_UNESCAPED_UNICODE) . "\n");

return;

}

}

}

$serv->close($fd);

}

});

$tcp_server->on('close', function ($serv, $fd) {

echo "Client: Close.\n";

});

$tcp_server->on('packet', function ($serv, $data, $addr) {

var_dump($data, $addr);

});

// $onRequest = new \serve\websocket\request\Message($server); //onRequest绑定

$server->on('request', function ($request, $response) use ($server) {

print_r('http\n');

$client = new \swoole_client(SWOOLE_SOCK_TCP);

if ($client->connect('127.0.0.1', 9503, 1)) {

$client->send("data");

echo $client->recv();

$client->close();

} else {

echo "connect failed.";

}

$response->end('fdsfdsf');

});

// echo "\n已经启动server->start\n";

$server->start();

// $this->insertDb();

}

public function onManagerStart($server) {

// 开启轮询读取redis缓存数据堆,执行批量写入数据库

// swoole_timer_tick(6000, function ($timer_id) {

// $this->insertDb();

// echo "tick-4000ms\n";

// });

echo "\n管理进程启动server->start,onManagerStart\n";

}

// 启动worker进程触发

public function onWorkerStart($server, $worker_id) {

echo "启动worker_id:$worker_id\n";

// if ($server->worker_id == 0) {

// }

}

public function onFinish($server, $task_id, $data) {

// print_r([$data, $task_id]);

echo "onFinish\n";

// print_r($response);

}

// 断开连接触发

public function onClose($server, $fd) {

echo "\nclient {$fd} closed.\n";

// if ($server->exist($fd)) {

// $server->push($fd, 0);

// }

$distributed = $server->websocketConfig['distributed'];

$fdInfo = $GLOBALS['client'][$fd];

if (is_array($fdInfo) && isset($fdInfo['uid'])) {

$clientInfo = $this->redis()->hGet("ws_clientInfo", $fdInfo['uid']);

echo "删除前\n";

print_r($fdInfo);

print_r($clientInfo);

if (!empty($clientInfo)) {

$source = $clientInfo['source'] ?? "app";

unset($clientInfo[$source]);

if (empty($clientInfo)) {

// 没有在线的用户 清空缓存

$this->redis()->hDel("ws_clientInfo", $fdInfo['uid']);

} else {

// 存在其他设备在线用户,只删除当前下线的用户缓存

$this->redis()->hSet("ws_clientInfo", $fdInfo['uid'], $clientInfo);

}

}

// $this->redis()->hDel("ws_fdInfo:" . $distributed['local']['ip'] . $distributed['local']['port'], $fd);

}

unset($GLOBALS['client'][$fd]);

echo "删除后\n";

print_r($this->redis()->hGet("ws_fdInfo:" . $distributed['local']['ip'] . $distributed['local']['port'], $fd));

print_r($this->redis()->hGet("ws_clientInfo", $fdInfo['uid']));

}

public function start() {

$this->server->start();

}

}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值