From 4a71b8b7fd4497e9d689e3c0eecfc35f7b5558eb Mon Sep 17 00:00:00 2001 From: zhoudw <zhoudw@infobird.com> Date: Tue, 21 Dec 2021 14:06:31 +0800 Subject: [PATCH] task --- config/config.php | 23 +++ .gitignore | 3 config/dev.php | 0 config/pro.php | 0 index.html | 75 ++++++++++++ logs/test.log | 1 start.sh | 2 ws_server.php | 239 +++++++++++++++++++++++++++++++++++++++ config/test.php | 0 9 files changed, 343 insertions(+), 0 deletions(-) diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..104fbb9 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +.DS_Store +logs/*/ +ws.out \ No newline at end of file diff --git a/config/config.php b/config/config.php new file mode 100644 index 0000000..aaccd7a --- /dev/null +++ b/config/config.php @@ -0,0 +1,23 @@ +<?php +/* + * @Author: your name + * @Date: 2021-12-15 11:33:00 + * @LastEditTime: 2021-12-21 13:40:02 + * @LastEditors: Please set LastEditors + * @Description: 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE + * @FilePath: /websocket/config/config.php + */ +return array( + //WebSocket绑定、分组、在线等信息存储使用的Redis配置 + 'redis' => array( + 'host' => '120.76.101.87', + 'port' => '51101' + ), + //本机WebSocket服务配置 + 'server_config' => array( + 'allow_ip' => '120.25.156.26:58003', + 'host' => '0.0.0.0', + 'port' => '9501', + ), + +); diff --git a/config/dev.php b/config/dev.php new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/config/dev.php diff --git a/config/pro.php b/config/pro.php new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/config/pro.php diff --git a/config/test.php b/config/test.php new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/config/test.php diff --git a/index.html b/index.html new file mode 100644 index 0000000..f204e5f --- /dev/null +++ b/index.html @@ -0,0 +1,75 @@ +<!DOCTYPE html> +<head> + <title>socket demo</title> + <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> + <script type="text/javascript" src="https://cdn.staticfile.org/jquery/1.10.2/jquery.min.js"></script> +</head> +<body> +<input type="text" id="msg" /> +<button id="send">发送</button> +</body> +</html> +<script> + $(function() + { + // 创建socket对象 + var socket = new WebSocket('ws://127.0.0.1:9501'); + + // 打开Socket + socket.onopen = function(event) + { + + $('#send').on('click', function() + { + var msg = $('#msg').val(); + var url = 'application/index/data'; + var fullData = { + url:url, + data:{ + session_id:'1a2e0ca9c7404b765a37a5ab07546fa8', + group_id:'1a2e0ca9c7404b765a37a5ab07546fa8', + msg:msg + } + }; + socket.send(JSON.stringify(fullData)); + console.log(msg); + }); + var url = 'application/index/reg'; + var fullData = { + url:url, + data:{ + session_id:'1a2e0ca9c7404b765a37a5ab07546fa8', + group_id:'1a2e0ca9c7404b765a37a5ab07546fa8' + } + }; + // 发送一个初始化消息 + socket.send(JSON.stringify(fullData)); + if (socket.readyState == 1) { + setInterval(function(){ + var fullData = { + url: 'plumeWSService/cluster/ping', + data: 'ping' + }; + socket.send(JSON.stringify(fullData)); + },1000) + } + // 监听消息 + socket.onmessage = function(event) { + if(event.data == 'pingpong'){//处理心跳接收事件 + + }else{ + var fullData = JSON.parse(event.data); + console.log("客户端监听到的消息:", fullData); + } + }; + + // 监听Socket的关闭 + socket.onclose = function(event) { + console.log("Socket关闭了", event); + }; + + // 关闭Socket.... + //socket.close() + }; + }); +</script> \ No newline at end of file diff --git a/logs/test.log b/logs/test.log new file mode 100644 index 0000000..d979aad --- /dev/null +++ b/logs/test.log @@ -0,0 +1 @@ +日志 \ No newline at end of file diff --git a/start.sh b/start.sh new file mode 100644 index 0000000..e70a8a2 --- /dev/null +++ b/start.sh @@ -0,0 +1,2 @@ +#!/bin/bash +php ws_server.php \ No newline at end of file diff --git a/ws_server.php b/ws_server.php new file mode 100644 index 0000000..6c22850 --- /dev/null +++ b/ws_server.php @@ -0,0 +1,239 @@ +<?php +/* + * @Author: zhoudw + * @Date: 2021-12-13 09:57:20 + * @Last Modified by: zhoudw + * @Last Modified time: 2021-12-13 09:58:34 + */ +class ws_server +{ + + protected $server; + protected $request; + protected $frame; + protected $server_config; + protected $redis = null; + protected $redis_config; + public function __construct() + { + $config = require './config/config.php'; + $this->server_config = $config['server_config']; + $this->redis_config = $config['redis']; + + $this->server = new Swoole\WebSocket\Server($this->server_config['host'], $this->server_config['port']); // swoole连接 + $this->server->set([ + 'task_worker_num' => 8, + 'enable_coroutine' => true, + 'task_enable_coroutine' => true + ]); + if (!$this->redis) { + $this->redis = new Redis(); + } + $this->server->on('start', function (Swoole\WebSocket\Server $server) { + echo "Websocket Server is started at ws://".$this->server_config['host'].":".$this->server_config['port']."\n"; + }); + + $this->server->on('message', function (Swoole\WebSocket\Server $server, $frame) { + $server->task($frame); + // $ret = array('code' => 0, 'data' => null); + // $msgData = $this->is_json($frame->data,true); + // if($msgData){ + // $frameData = $msgData; + // $this->dealMsg($frameData,$frame->fd); + // }else{ + // $ret['code'] = -1; + // $ret['msg'] = 'data is null or data no json'; + // $server->push($frame->fd, json_encode($ret)); + // return; + // } + }); + + $this->server->on('task', function ($server, $task) { + $ret = array('code' => 0, 'data' => null); + $frame = $task->data; + $msgData = $this->is_json($frame->data,true); + if($msgData){ + $frameData = $msgData; + $this->dealMsg($frameData,$frame->fd); + }else{ + $ret['code'] = -1; + $ret['msg'] = 'data is null or data no json'; + $server->push($frame->fd, json_encode($ret)); + return; + } + }); + $this->server->on('close', function ($ser, $fd) { + $host = $this->server_config['allow_ip']; + $this->redis->connect($this->redis_config['host'],$this->redis_config['port'] ); + $group_key = $this->redis->get($host.':'.$fd.':group'); + $this->redis->lrem($group_key,$fd,0); + }); + + $this->server->start(); + + } + + /** + * 功能:1、判断是否是json + * @param string $data + * @param bool $assoc + * @return bool|mixed|string + */ + function is_json($data = '', $assoc = false) + { + $data = json_decode($data, $assoc); + if ($data && (is_object($data)) || (is_array($data) && ! empty(current($data)))) { + return $data; + } + return false; + } + + /** + * 功能:1、消息处理 + */ + public function dealMsg($msgContent,$fd){ + $ret = array('code' => 0, 'data' => null); + // $this->server->push($fd,json_encode($ret)); + $url = $msgContent['url']; + $data = $msgContent['data']; + $action = substr($url, strrpos($url, "/") + 1); + $this->log('action','ws','ws',$action); + switch ($action) + { + case "reg": + $this->log('reg','reg','ws',['content'=>$msgContent,'fd'=>$fd]); + $groupId = $data['group_id']; + $session = $data['session_id']; + $this->bind($groupId,'',$fd); + $key = "practice_scenes_ws_cur_session_info:".$session; + $node_key = 'practice_scenes_ws_cur_session_node_info:'.$session; + $redisData = $this->redis->get($key); + if($redisData){ + $ret['data'] =json_decode($redisData,true); + $this->redis->del($key); + }else{ + $redisData = $this->redis->get($node_key); + $ret['data'] =json_decode($redisData,true); + } + $ret['event'] = "re_bind"; + $this->replay($fd,$ret); + break; + case "data": + $this->log('data','data','ws',['content'=>$msgContent,'fd'=>$fd]); + $groupId = $data['group_id']; + $ret['event'] = "data"; + $ret['data'] = $data; + $this->broadcastself($ret , $groupId); + break; + case "ping": + $this->replay($fd,$data.'pong', false); + break; + default: + $ret['code'] = 404; + $ret['msg'] = 'event no existent'; + $this->server->push($fd,json_encode($ret)); + return; + } + } + + + /** + * 当前链接的绑定事件。 + * 绑定的几种状态: + * 1.无分组 + * host -> fds (获取当前节点的在线链接列表) + * host:fd -> value (获取当前节点当前链接的绑定数据) + * host:fd:group -> host (获取当前节点当前链接的绑定分组) + * 2.有分组 + * groupID:host -> fds + * host:fd -> value + * host:fd:group -> groupID:host + * @param string $groupID 需要绑定当前链接所在分组的分组标识,如果为空则使用默认分组 + * @param string $value 需要绑定当前链接对应的业务数据,如果为空则不绑定 + */ + public function bind($groupID = '', $value = '',$fd){ + $this->redis->connect($this->redis_config['host'],$this->redis_config['port'] ); + $host = $this->server_config['allow_ip']; + // 绑定分组和当前链接对应的分组标识 + if(empty($groupID)){ + $this->redis->rpush($host, $fd); + $this->redis->set($host.':'.$fd.':group', $host); + }else{ + $this->redis->rpush($groupID.':'.$host, $fd); + $this->redis->set($host.':'.$fd.':group', $groupID.':'.$host); + } + // 绑定业务数据 + if(!empty($value)){ + $this->redis->set($host.':'.$fd, $value); + } + } + + /** + * 对指定数据和分组对当前集群节点进行广播。 + * @param \stdClass $data 广播数据 + * @param string $groupID 分组标识 + */ + public function broadcastself($data, $groupID = '') { + $host = $this->server_config['allow_ip']; + $connections = array(); + if(empty($groupID)){ + // 获取所有无分组标识在线终端 + $onlines = count($this->server->connections); + if ($onlines > 0) { + $connections = $this->server->connections; + } + }else{ + // 获取所有分组标识在线终端 key = groupID:host + $key = $groupID . ':' . $host; + try { + $this->redis->connect($this->redis_config['host'],$this->redis_config['port'] ); + $connections = $this->redis->lrange($key, 0, -1); + if (!is_array($connections)) {//redis异常 + $this->log('redis异常','ws','broadcastself',['key'=>$key,'data'=>$data]); + return; + } + } catch (\Exception $e) { + $this->log('redis异常','ws','broadcastself',['key'=>$key,'data'=>$data,'msg'=>$e->getMessage()]); + return; + } + } + if(is_array($data)){ + $data['group_id'] = $groupID; + }else{ + $data->group_id = $groupID; + } + $connections = array_unique($connections); + // 广播获取的在线终端 + foreach ($connections as $fd) { + $this->server->push($fd,json_encode($data)); + } + } + /** + * 回复当前链接。 + * @param \stdClass $data 回复数据 + * @param bool $encode 如果$data是string格式,则encode为false + */ + public function replay($fd,$data,$encode = true) { + $json_data = $data; + if($encode){ + $json_data = json_encode($data, JSON_UNESCAPED_UNICODE); + } + $this->server->push($fd, $json_data); + } + + function log($title,$folder,$finename,$msg) + { + $logs = json_encode($msg); + $msg = "[".date('Y-m-d H:i:s')."]\t- INFO - ".$title." - ".$logs."\n"; + //判断目的文件夹是否存在? 如果不存在就生成 + //简单处理: 实际应用需要修改 + $dst ='./logs/'.$folder; + if (is_dir($dst) === FALSE) { + @mkdir($dst, 0777, true); + } + $log_file_name = $dst.'/'.$finename.'-'.date('Y-m-d').'.log'; + return @file_put_contents($log_file_name, $msg, FILE_APPEND); + } +} +$ws = new ws_server(); +?> \ No newline at end of file -- Gitblit v1.8.0