美文网首页
15.Swoole+PHP7+Redis+ThinkPHP5.1

15.Swoole+PHP7+Redis+ThinkPHP5.1

作者: 一枼落知天下 | 来源:发表于2019-06-28 00:27 被阅读0次

192.168.31.62    Swoole+PHP7+Redis
192.168.31.63    Swoole+PHP7
192.168.31.64    Nginx+HTML

Nginx配置

upstream liveChartWS {
        server 192.168.31.62:8080;
        server 192.168.31.63:8080;
    }

    server {
        listen       80;
        server_name  live.zhou.com;

        #charset koi8-r;

        access_log  logs/host.access.log  main;

        location  ~ \/(live|chart)$ {
            proxy_pass http://liveChartWS;
            proxy_http_version 1.1;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection "upgrade";
        }

        location / {
            root   /home/thinkPHP/public/static;
            index  index.html index.htm;
            if (!-e $request_filename){
              proxy_pass http://liveChartWS;
            }
        }
}

启动swoole

  netstat -anp 2>/dev/null | grep 8080 | grep LISTEN |wc -l
  nohup /usr/local/bin/php /home/thinkPHP/server/ws.php >> /home/thinkPHP/server/logs/SERVER-`date +%Y-%m-%d`.log 2>&1 & 
目录结构

reload.sh

#! /usr/bin/env bash
echo "Loading..."
pid=`pidof LIVE_MASTER`
echo $pid
kill -USR1 $pid
echo "Loading Success"

HTTP WEBSOCKET SERVER

<?php
/**
 * WebSocket
 * netstat -anp 2>/dev/null | grep 8080 | grep LISTEN |wc -l
 * 
 * nohup /usr/local/bin/php /home/thinkPHP/server/ws.php >> /home/thinkPHP/server/logs/SERVER-`date +%Y-%m-%d`.log 2>&1 & 
 */

class Ws 
{
    CONST HOST = "0.0.0.0";
    CONST PORT = 8080;

    public $ws    = null;
    public $redis = null;

    public function __construct(){
        //创建websocket服务器对象,监听0.0.0.0:9502端口
        $this->ws = new swoole_websocket_server(self::HOST,self::PORT);
        $this->ws->set(
            [
                'worker_num'=>4,
                'task_worker_num'=>4,
                'enable_static_handler'=>true,
                'document_root'=> "/home/thinkPHP/public/static",
            ]
        );

        
        $this->ws->on('start',[$this,'onStart']);
        $this->ws->on('workerStart',[$this,'onWorkerStart']);
        $this->ws->on('open',[$this,'onOpen']);
        $this->ws->on("message",[$this,"onMessage"]);
        $this->ws->on("request",[$this,"onRequest"]);
        $this->ws->on("task",[$this,"onTask"]);
        $this->ws->on("finish",[$this,"onFinish"]);
        $this->ws->on("close",[$this,"onClose"]);

        $this->redis = new \Redis();
        $result = $this->redis->connect('192.168.31.62',6379,10);
        if ($result == false){
            throw new \Exception("Redis connect error");
        }
        $this->redis->del('live');
        $this->redis->del('chart');
        $this->redis->close();
        $this->redis = null;

        $this->ws->start();
    }

    public function onStart($server){
        // echo "Master_pid: {$server->master_pid}-Manager_pid:{$server->manager_pid}\n";
        swoole_set_process_name("LIVE_MASTER");
    }


    /**
     * [onWorkerStart 回调]
     * @author Jhou Shuai
     * @datetime 2019-06-24T13:58:54+0800 
     */
    public function onWorkerStart($server,$worker_id){
        // 加载基础文件
        require __DIR__ . '/../thinkphp/base.php';
    }


    /**
     * [onRequest 回调]
     * @author Jhou Shuai
     * @datetime 2019-06-24T14:00:23+0800
     */
    public function onRequest($request, $response){
        if ($request->server['request_uri']=='/favicon.ico'){
            $response->status(404);
            $response->end();
            return ;
        }

        $_GET = $_POST = [];

        if(isset($request->server)){
            foreach ($request->server as $key => $value) {
                $_SERVER[strtoupper($key)] = $value;
            }
        }

        if(isset($request->header)){
            foreach ($request->header as $key => $value) {
                $_SERVER[strtoupper($key)] = $value;
            }
        }

        if(isset($request->get)){
            foreach ($request->get as $key => $value) {
                $_GET[$key] = $value;
            }
        }

        
        if(isset($request->post)){
            foreach ($request->post as $key => $value) {
                $_POST[$key] = $value;
            }
        }
        
        $_FILE = [];
        if(isset($request->files)){
            foreach ($request->files as $key => $value) {
                $_FILE[$key] = $value;
            }
        }

        $_POST['http_server'] = $this->ws;

        ob_start();

        try{
            // 执行应用并响应
            think\Container::get('app')->run()->send();
        }catch(\Exception $e){
            //todo
        }
        $res = ob_get_contents();
        ob_end_clean();


        $response->header("Content-Type", "text/html; charset=utf-8");
        $response->end($res);
    }

    /**
     * [onOpen 监听WebSocket连接打开事件]
     * @author Jhou Shuai
     * @datetime 2019-06-24T13:58:54+0800
     * @param    [type]                   $ws     
     * @param    [type]                   $repuest 
     */
    public function onOpen($ws,$request){
        if (!empty($request->server['path_info'])) {
            $key = trim(ltrim($request->server['path_info'], '/'));
            print_r($key."==>".$request->fd."\n");
            app\common\lib\Redis::getInstance()->sAdd($key,$request->fd);
        }else{
            $ws->push($request->fd, "服务器连接错误~~~");
        }
    }


    /**
     * [onMessage 监听WebSocket消息事件]
     * @author Jhou Shuai
     * @datetime 2019-06-24T14:00:23+0800
     * @param    [type] $ws    
     * @param    [type] $frame 
     */
    public function onMessage($ws,$frame){
        // 接收到客户端的消息,下面的业务逻辑
        echo "Message: {$frame->data}-Date:".date("Y-m-d")."\n";
        // 接收到客户端的消息,下面的业务逻辑,非常耗时 
        // todo 10s
        // swoole Task机制
        // $data = [
        //  'task'=>1,
        //  'fd'=>$frame->fd,
        // ];
        // $ws->task($data);
        // 
        // $ws->push($frame->fd, "Server: {$frame->data} Date:".date("Y-m-d  H:i:s"));
    }

    /**
     * [onClose 监听WebSocket连接关闭事件]
     * @author Jhou Shuai
     * @datetime 2019-06-24T14:01:29+0800
     * @param    [type]                   $ws 
     * @param    [type]                   $fd 
     */
    public function onClose($ws, $fd){
        echo "client-{$fd} is closed\n";
        app\common\lib\Redis::getInstance()->sRem("live",$fd);
        app\common\lib\Redis::getInstance()->sRem("chart",$fd);
    }

    /**
     * [onTask ]
     * @author Jhou Shuai
     * @datetime 2019-06-24T14:49:27+0800
     * @param    [type]                   $ws      
     * @param    [type]                   $taskId   
     * @param    [type]                   $workerId 
     * @param    [type]                   $data     
     */
    public function onTask($serv,$taskId,$workerId,$data){
        print_r($data);
        sleep(10);
        return "On Task Finish";
    }

    /**
     * [onFinish ]
     * @author Jhou Shuai
     * @datetime 2019-06-24T14:51:48+0800
     * @param    [type]                   $serv   
     * @param    [type]                   $taskId 
     * @param    [type]                   $data   
     */
    public function onFinish($serv,$taskId,$data){
        echo "{$taskId}-{$data}--Succ Task\n";
    }
}

new Ws();

Index.php

<?php
namespace app\index\controller;

use app\common\lib\Util;

class Index extends \think\Controller
{
    
    public function index(){
        return Util::return_client(config('code.success'),'成功!',$_GET);
    }

    public function hello($name = 'ThinkPHP5')
    {
        print_r(request()->get());
        print_r(request()->post());
        return 'hello,' . $name;
    }
}

Live.php

<?php
namespace app\index\controller;

use app\common\lib\Util;
use app\common\lib\Redis;

class Live extends \think\Controller
{
    
    public function push(){
        $msg = request()->get('msg');
        // 把数据push到直播页面。
        // todo 业务逻辑~~~~
        $info = !empty($msg)?trim($msg):"你有新短消息来啦~~~";
        $server = $_POST['http_server'];
        // $server->task();
        $client = Redis::getInstance()->sMembers(config("redis.live"));
        foreach ($client as $key => $fd) {
            $server->push($fd,$info);
        }
        return Util::return_client(config('code.success'),'Push Live Msg Success~~',$client);
    }

}

Chart.php

<?php
namespace app\index\controller;

use app\common\lib\Util;
use app\common\lib\Redis;

class Chart extends \think\Controller
{
    
    public function send(){
        $msg = request()->get('msg');
        // 把数据push到聊天专用页面。
        // todo 业务逻辑~~~~
        $info = !empty($msg)?trim($msg):"你有新短消息来啦~~~";
        $server = $_POST['http_server'];
        // $server->task();
        $client = Redis::getInstance()->sMembers(config("redis.chart"));
        foreach ($client as $key => $fd) {
            $server->push($fd,$info);
        }
        return Util::return_client(config('code.success'),'Send Chart Msg Success~~',$client);
    }

}

Redis.php

<?php

namespace app\common\lib;

class Redis {

    public $redis = "";
    /**
     * 定义单例模式的变量
     * @var null
     */
    private static $_instance=null;

    private function __construct(){
        $this->redis = new \Redis();
        $result = $this->redis->connect('192.168.31.62',6379,10);
        if ($result == false){
            throw new \Exception("Redis connect error");
            
        }
    }


    public static function getInstance() {
        if(empty(self::$_instance)){
            self::$_instance = new self();
        }
        return self::$_instance;
    }

    public function get($key){
        # code...
    }

    public function sAdd($key,$value){
        return $this->redis->sAdd($key,$value);
    }

    public function sRem($key,$value){
        return $this->redis->sRem($key,$value);
    }

    public function sMembers($key)
    {
        return $this->redis->sMembers($key);
    }

    /**
     * 清空当前数据库
     * @return bool
     */
    public function flushDB(){
        return $this->redis->flushDB();
    }

    public function del($key){
        return $this->redis->del($key);
    }

    /**
     * [__destruct 释放连接]
     * @author Jhou Shuai
     */
    private function __destruct() {
       $this->redis->close();
    }
}

Util.php

<?php

namespace app\common\lib;

class Util {

    /**
     * [return_client 给客户端输出数据]
     * @author Jhou Shuai
     * @datetime 2019-06-25T16:53:59+0800
     */
    public static function return_client($status,$msg='',$data=[]){
        $result = [
            'status'   => $status,
            'message'  => $msg,
            'data'     => $data,    
            'curtime'  => date("Y-m-d,H:i:s"),
        ];
        return json_encode($result);
    }

}

config/code.php

<?php


return [
    "success" => '0000',
    "error"   => '1000',
];

config/redis.php

<?php

return [
    'host'        => '192.168.31.62',
    'password'    => '',
    'port'        => 6379,
    'timeout'     => 5,
    'live'        =>'live',
    'chart'       =>'chart',
];

index.html

<!DOCTYPE html>
<html>
<head>
<title>玫瑰之约<Swoole.WebSocket.JhouShuai></title>
<meta charset="utf-8">
<link rel="shortcut icon" href="/favicon.ico" type="image/x-icon" /> 
</head>
<body>
<h1>玫瑰之约~~来啦,老弟!@JhouShuai</h1>
<p style="text-align: center;">
<canvas id="c" height="500" width="500"></canvas>
<script>
 var b = document.body;
 var c = document.getElementsByTagName('canvas')[0];
 var a = c.getContext('2d');
 document.body.clientWidth;
</script>
<script>
with(m=Math)C=cos,S=sin,P=pow,R=random;c.width=c.height=f=500;h=-250;function p(a,b,c){if(c>60)return[S(a*7)*(13+5/(.2+P(b*4,4)))-S(b)*50,b*f+50,625+C(a*7)*(13+5/(.2+P(b*4,4)))+b*400,a*1-b/2,a];A=a*2-1;B=b*2-1;if(A*A+B*B<1){if(c>37){n=(j=c&1)?6:4;o=.5/(a+.01)+C(b*125)*3-a*300;w=b*h;return[o*C(n)+w*S(n)+j*610-390,o*S(n)-w*C(n)+550-j*350,1180+C(B+A)*99-j*300,.4-a*.1+P(1-B*B,-h*6)*.15-a*b*.4+C(a+b)/5+P(C((o*(a+1)+(B>0?w:-w))/25),30)*.1*(1-B*B),o/1e3+.7-o*w*3e-6]}if(c>32){c=c*1.16-.15;o=a*45-20;w=b*b*h;z=o*S(c)+w*C(c)+620;return[o*C(c)-w*S(c),28+C(B*.5)*99-b*b*b*60-z/2-h,z,(b*b*.3+P((1-(A*A)),7)*.15+.3)*b,b*.7]}o=A*(2-b)*(80-c*2);w=99-C(A)*120-C(b)*(-h-c*4.9)+C(P(1-b,7))*50+c*2;z=o*S(c)+w*C(c)+700;return[o*C(c)-w*S(c),B*99-C(P(b, 7))*50-c/3-z/1.35+450,z,(1-b/1.2)*.9+a*.1, P((1-b),20)/4+.05]}}setInterval('for(i=0;i<1e4;i++)if(s=p(R(),R(),i%46/.74)){z=s[2];x=~~(s[0]*f/z-h);y=~~(s[1]*f/z-h);if(!m[q=y*f+x]|m[q]>z)m[q]=z,a.fillStyle="rgb("+~(s[3]*h)+","+~(s[4]*h)+","+~(s[3]*s[3]*-80)+")",a.fillRect(x,y,1,1)}',0)
</script>
</p>
<script type="text/javascript">
(function(win) {
    var Client = function(options) {
      var MAX_CONNECT_TIMES = 10;
      var DELAY = 15000;
      this.options = options || {};
      this.createConnect(MAX_CONNECT_TIMES, DELAY);
    }

    Client.prototype.createConnect = function(max, delay) {
        var self = this;
        if (max === 0) {
          return;
        }

        connect();

        function connect() {
            var domain = document.domain;
            var ws = new WebSocket('ws://'+domain+'/live');
            ws.onopen = function() {
                auth();
                register();
            }

            ws.onmessage = function(evt) {
                var data = evt.data;
                var notify = self.options.notify;
                if(notify) notify(data);
            }

            ws.onclose = function() {
                console.log("连接断开咯~~~重连中~~~")
                setTimeout(reConnect, delay);
            }

            function auth() {
                // 可以做认证
                ws.send("帅哥请求进入~~~");
            }

            function register() {
                // 注册
                ws.send("小可爱来啦~~~~");
            }
        }

        function reConnect() {
            self.createConnect(--max, delay * 2);
        }
    }

  win['MyClient'] = Client;
})(window);
var client = new MyClient({
  notify: function(data) {
    console.log(data);
    alert(JSON.stringify(data));
  }
});
</script>
</body>
</html>

chart.html

<!DOCTYPE html>
<html>
<head>
<title>小嘴抹蜜,口吐芬芳~~<Swoole.WebSocket.JhouShuai></title>
<meta charset="utf-8">
<link rel="shortcut icon" href="/favicon.ico" type="image/x-icon" /> 
</head>
<body>
<h1>小嘴抹蜜,口吐芬芳~~@JhouShuai</h1>
<p style="text-align: center;">
<canvas id="c" height="500" width="500"></canvas>
<script>
 var b = document.body;
 var c = document.getElementsByTagName('canvas')[0];
 var a = c.getContext('2d');
 document.body.clientWidth;
</script>
<script>
with(m=Math)C=cos,S=sin,P=pow,R=random;c.width=c.height=f=500;h=-250;function p(a,b,c){if(c>60)return[S(a*7)*(13+5/(.2+P(b*4,4)))-S(b)*50,b*f+50,625+C(a*7)*(13+5/(.2+P(b*4,4)))+b*400,a*1-b/2,a];A=a*2-1;B=b*2-1;if(A*A+B*B<1){if(c>37){n=(j=c&1)?6:4;o=.5/(a+.01)+C(b*125)*3-a*300;w=b*h;return[o*C(n)+w*S(n)+j*610-390,o*S(n)-w*C(n)+550-j*350,1180+C(B+A)*99-j*300,.4-a*.1+P(1-B*B,-h*6)*.15-a*b*.4+C(a+b)/5+P(C((o*(a+1)+(B>0?w:-w))/25),30)*.1*(1-B*B),o/1e3+.7-o*w*3e-6]}if(c>32){c=c*1.16-.15;o=a*45-20;w=b*b*h;z=o*S(c)+w*C(c)+620;return[o*C(c)-w*S(c),28+C(B*.5)*99-b*b*b*60-z/2-h,z,(b*b*.3+P((1-(A*A)),7)*.15+.3)*b,b*.7]}o=A*(2-b)*(80-c*2);w=99-C(A)*120-C(b)*(-h-c*4.9)+C(P(1-b,7))*50+c*2;z=o*S(c)+w*C(c)+700;return[o*C(c)-w*S(c),B*99-C(P(b, 7))*50-c/3-z/1.35+450,z,(1-b/1.2)*.9+a*.1, P((1-b),20)/4+.05]}}setInterval('for(i=0;i<1e4;i++)if(s=p(R(),R(),i%46/.74)){z=s[2];x=~~(s[0]*f/z-h);y=~~(s[1]*f/z-h);if(!m[q=y*f+x]|m[q]>z)m[q]=z,a.fillStyle="rgb("+~(s[3]*h)+","+~(s[4]*h)+","+~(s[3]*s[3]*-80)+")",a.fillRect(x,y,1,1)}',0)
</script>
</p>
<script type="text/javascript">
(function(win) {
    var Client = function(options) {
      var MAX_CONNECT_TIMES = 10;
      var DELAY = 15000;
      this.options = options || {};
      this.createConnect(MAX_CONNECT_TIMES, DELAY);
    }

    Client.prototype.createConnect = function(max, delay) {
        var self = this;
        if (max === 0) {
          return;
        }

        connect();

        function connect() {
            var domain = document.domain;
            var ws = new WebSocket('ws://'+domain+'/chart');
            ws.onopen = function() {
                auth();
                register();
            }

            ws.onmessage = function(evt) {
                var data = evt.data;
                var notify = self.options.notify;
                if(notify) notify(data);
            }

            ws.onclose = function() {
                console.log("连接断开咯~~~重连中~~~")
                setTimeout(reConnect, delay);
            }

            function auth() {
                // 可以做认证
                ws.send("帅哥进入聊天室~~~");
            }

            function register() {
                // 注册
                ws.send("嘤嘤嘤进入聊天室~~~~");
            }
        }

        function reConnect() {
            self.createConnect(--max, delay * 2);
        }
    }

  win['MyClient'] = Client;
})(window);
var client = new MyClient({
  notify: function(data) {
    console.log(data);
    alert(JSON.stringify(data));
  }
});
</script>
</body>
</html>

最终效果:

相关文章

网友评论

      本文标题:15.Swoole+PHP7+Redis+ThinkPHP5.1

      本文链接:https://www.haomeiwen.com/subject/npudcctx.html