websocket 应用实例

1. 服务端

class WebSocketServer
{
    public $server;


    public function __construct($controller) {
        $this->server = new \swoole_websocket_server("0.0.0.0", 9501);
        $this->server->set(array(
            'worker_num' => 8,
            'daemonize' => false,
//            'heartbeat_check_interval' => 30,
//            'heartbeat_idle_time' => 90,
            'heartbeat_check_interval' => 60,
            'heartbeat_idle_time' => 600,
        ));

        $this->server->on('WorkerStart', array($controller, 'onWorkerStart'));
        $this->server->on('open', array($controller, 'onOpen'));
        $this->server->on('message',array($controller, 'onMessage') );
        $this->server->on('close',array($controller, 'onClose') );
        $this->server->on('request', array($controller, 'onRequest'));
        $this->server->on('Timer', array($controller, 'onTimer'));
    }

    public function start(){

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

}

class ServerController extends Controller
{

    private $fdKey='swoole_websocket_server_fd';
    private $userIdKey='swoole_websocket_server_userId';

    const GPS_POINT_KEY = "GPS:GPSPOINT";   // 实时坐标点的标识

    public function start()
    {
        try{
            $server = new WebSocketServer($this);
            $server->start();
        }catch(\Exception $e) {
            $this->log("websocket:Caught exception000:".$e->getMessage());
        }
    }

    public function onWorkerStart( $server , $worker_id)
    {
        // 在Worker进程开启时绑定定时器
        echo "onWorkerStart\n";
        // 只有当worker_id为0时才添加定时器,避免重复添加
        if ($worker_id == 0) {
            $server->addtimer(1000);
        }
    }

    public function onTimer($server, $interval) {
        switch( $interval ) {
            case 1000: {	//
                echo "Do Thing A at interval 30000\n";
                $this->pushData($server);
                break;
            }
        }
    }

    public function onOpen(\swoole_websocket_server $server, $request) {
        echo "server: handshake success with fd{$request->fd}\n";

        try{
            $server = $request->server;
            $uri = trim($server['request_uri'],'/');
            $user = explode('/',$uri);
            $userId = $user[1];

            $redis = Cache::getInstance();
            $fdArr = $redis->get($this->fdKey.$userId);

            $fd = $request->fd;
            if(!empty($fdArr)){
                array_push($fdArr,$fd);
                $newFdArr = $fdArr;
            }else{
                $newFdArr = array($fd);
            }

            $redis->set($this->fdKey.$userId,$newFdArr);
            $redis->set($this->userIdKey.$fd,$userId);

            $this->log("websocket:server start, fd:".$request->fd);
        }catch(\Exception $e) {
            $this->log("websocket:Caught exception000:".$e->getMessage());
        }
    }


    public function onMessage(\swoole_websocket_server $server, $frame) {
        echo "receive from {$frame->fd}:{$frame->data},opcode:{$frame->opcode},fin:{$frame->finish}\n";
        try{
           $data = $frame->data;
           if($data=='close'){
               $redis = Cache::getInstance();

               $key = $this->userIdKey.$frame->fd;
               $userId = $redis->get($key);
               $redis->rm($key);
               $redis->rm($this->fdKey.$userId);
           }

        }catch(\Exception $e){
            $this->log("websocket:Caught exception111:".$e->getMessage());
        }
    }

    public function onClose($ser,$fd) {
        echo "client {$fd} closed\n";


        $redis = Cache::getInstance();
        $redis->rm('swoole_websocket_server_fd1');

        $key = $this->userIdKey.$fd;
        $userId = $redis->get($key);
        $redis->rm($key);

        $fdKey = $this->fdKey.$userId; //团队下的fd
        $fdArr = $redis->get($fdKey);
        if(!empty($fdArr)&&in_array($fd,$fdArr)){
            $fd = arrray($fd);
            $newFdArr = array_diff($fdArr,$fd);
            if(!empty($newFdArr)){
                $redis->set($fdKey,$newFdArr);
            }else{
                $redis->rm($fdKey);
            }
        }

        $this->log("websocket:server close:".date("Y-m-d H:i:s"));
    }

    public function onRequest($request, $response) {
        // 接收http请求从get获取message参数的值,给用户推送
        // $this->server->connections 遍历所有websocket连接用户的fd,给所有用户推送
        foreach ($this->server->connections as $fd) {
            $this->server->push($fd, $request->get['message']);
        }
    }


    public function pushData($server){
        $redis = Cache::getInstance();
        $all = $redis->hGetAll(self::GPS_POINT_KEY);

        foreach($all as $key=>$val){

            if(!empty($val)){
                list($lonlat, $gateTime) = explode('|', $val);
                list($lon, $lat) = explode(',', $lonlat);

                $latitude = "$lat";
                $longitude = "$lon";

                if($gateTime+60>time()){//60s内的算坐标更新了
                    if(strlen($key)==11){ //手机
                        //取得对应在线手机所在的团队id
                        $where = ['id_card'=>$key,'state'=>1];
                    }elseif(strlen($key)==15){ //定位神器
                        //取得对应在线手机所在的团队id
                        $where = ['device_imei'=>$key,'state'=>1];
                    }
                    $deviceData = PointDeviceService::getOnlineDevice($where);

                    $deviceData['record'] = [
                        'gate_time'=>date("Y-m-d H:i:s", $gateTime),
                        'latitude'=>$latitude,
                        'longitude'=>$longitude,
                    ];

                    print_r($deviceData);

                    $jsonData = json_encode($deviceData);

                    echo $userId = $deviceData['user_id'];//团队ID

                    $fdArr = $redis->get($this->fdKey.$userId);
                    echo "aaa:";print_r($fdArr);
                    if(!empty($fdArr)){
                        foreach($fdArr as $fd){
                            $server->push($fd,$jsonData);
                        }
                    }
                    $this->log("websocket:server push data:".$jsonData);
                }else{
                    $this->log("websocket:".$key."设备没有更新的坐标数据");
                }
            }
        }
    }



    private function log($message=''){
        $trueDir = RUNTIME_PATH.'websocketServer'.DIRECTORY_SEPARATOR;
        if(!is_dir($trueDir)){
            mkdir($trueDir,0777,true);
        }
        $file = date('Y_m_d').'.log';
        $trueFile = $trueDir.$file;

        $message = date("Y-m-d H:i:s").":".$message;
        file_put_contents($trueFile,$message.PHP_EOL,FILE_APPEND);
    }

}


2. 客户端

function wsConnect(){
       // var userId = '{userId}';
        var wsServer = 'ws://127.0.0.1:9501/user_id/1';
        var websocket = new WebSocket(wsServer);
        return websocket;
    }

    //在地图上动态显示所有在线设备 add by mzc 2017.10.19
    function dynamicDisplay(){

        websocket =  wsConnect();

        websocket.onopen = function (evt) {
            if(websocket.readyState==1){
                websocket.send('user_id=1');
                console.log("websocket连接成功");
            }
        };

        websocket.onclose = function (evt) {
            console.log("Disconnected");
            if(websocket.readyState==3){
                websocket.send('close');
                wsConnect();
                console.log('reconnect');
            }
        };

        websocket.onmessage = function (evt) {
            console.log('服务器推送过来的数据: ' + evt.data);
            var data = evt.data;
            data = eval('(' + data + ')');

            var temp = [];
//            for (var i = 0; i <data.length; i++) {
//                temp.push(data[i]);
//            }
            temp.push(data);
            openInfo(temp);
        };

        websocket.onerror = function (evt, e) {
            console.log('Error occured: ' + evt.data);
            if(websocket.readyState==3){
                wsConnect();
                console.log('reconnect');
            }
        };

        //关闭页面时记得一定要关闭连接,否则服务端可能不会释放
        window.onunload = function(){
            websocket.close();
        };
    }


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值