已掉线,重新登录

首页 > 绿虎论坛 > 杂类 > 超级灌水 (发帖)

标题: [精]简易多用户websocket服务端

作者: @Ta

时间: 2019-05-09

点击: 4181

ThinkPHP5.0.24+Workman
015e9f44a5734741b91320e47ce5546c62829.png
服务端代码.
<?php
namespace app\socket\controller;

use think\worker\Server;
class Index extends Server
{
    protected $socket = 'websocket://127.0.0.11:8001';
    /**
     * 收到信息
     * @param $connection
     * @param $data
     */
    public function onMessage($connection, $data)
    {
        if(!json_decode($data,true))
        {
            return ;
        }
        $client=json_decode($data,true);

        if(!isset($client['msg']))
        {
            return;
        }

        $param=[
            'type'=>'speak',
            'speaker_uid'=>$connection->uid,
            'speaker_msg'=>$client['msg']
        ];
        //除了那个新来的不通知
        $this->radio($this->AopReturn($param),$connection->uid);

        echo '收到客户端UID'.$connection->uid.'->'.$data."\n";
    }

    /**
     * 当连接建立时触发的回调函数
     * @param $connection
     */
    public function onConnect($connection)
    {
        $connection->uid =$this->uin++;  //给于这个用户一个唯一的UID

        $param=[
            'type'=>'join',
            'new_uid'=>$connection->uid
        ];
        //除了那个新来的不通知
        $this->radio($this->AopReturn($param),$connection->uid);

        echo '客户端连接UID:'.$connection->uid."\n";
    }


    /**
     * 当连接断开时触发的回调函数
     * @param $connection
     */
    public function onClose($connection)
    {
        $param=[
            'type'=>'exit',
            'uid'=>$connection->uid
        ];
        //除了那个离线的的不通知
        $this->radio($this->AopReturn($param),$connection->uid);

        echo '客户端断开UID:'.$connection->uid."\n";
    }


    public function AopReturn($array)
    {
        return json_encode($array);
    }


    /**
     * @param $msg广播
     */
    public function radio($msg,$unset_uid=0)
    {
        foreach ($this->worker->connections as $each)
        {
            if($each->uid==$unset_uid)
            {
                continue;
            }
            $each->send($msg);
        }
    }

    /**
     * 当客户端的连接上发生错误时触发
     * @param $connection
     * @param $code
     * @param $msg
     */
    public function onError($connection, $code, $msg)
    {
        echo "error $code $msg\n";
    }

    /**
     * 每个进程启动
     * @param $worker
     */
    public function onWorkerStart($worker)
    {

        echo  '进程启动>>>>>>>>>>>>>>>>>>>>>>>>>'."\n";
        return ;
        echo '进程启动'.json_encode($worker)."\n";
    }

}





客户端:
<html><head>
    <meta charset="utf-8">
    <title>设置我的资料</title>
    <meta name="renderer" content="webkit">
    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
    <meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=0">
    <script src="/static/js/jq.js"></script>
    <link rel="stylesheet" href="/static/layuiadmin/layui/css/layui.css" media="all">
    <link rel="stylesheet" href="/static/layuiadmin/style/admin.css" media="all">

    <script src="/static/layuiadmin/layui/layui.js"></script>
</head>
<body layadmin-themealias="default">

<div class="layui-container">
    <h1 align="center">在线聊天</h1>
    <div style="min-height: 60%" class="chatdiv"></div>
    <div align="center">
        <textarea name="msg" id="msg" cols="30" rows="10">这里写信息</textarea><br>
        <button class="layui-btn  layui-btn-primary" id="send">发信消息</button>
    </div>
</div>
<script>
     websocket=function(){
         this.ws;

         this.init=function () {
             this.wsConnect();//连接请求动作发送
             this.wsConnectSuccess();//成功连接到服务器
         }

         /**
          * 连接请求动作发送
          */
         this.wsConnect=function ()
         {
             console.log('本地:正在尝试连接');
             this.ws = new WebSocket("ws://127.0.0.11:8001");
         }

         /**
          * 成功连接到服务器
          */
         this.wsConnectSuccess=function()
         {
             this.ws.onopen = function(event) {
                 console.log('本地:连接远程服务器成功');
                 this.onMessage();//来消息监听
                 this.sendMessage();//发送消息监听
                 this.sendBtnStatus();//按钮监听
             }.bind(this);
         }


         this.onMessage=function () {
             this.ws.onmessage = function(event)
             {
                 this.onMessageEvent(event.data);
             }.bind(this)
         }

         this.onMessageEvent=function (string)
         {

             console.log("服务器:主动推送->"+string);
             data=eval('('+ string +')');

             //data=JSON.parse(string);
             if(data.type=='speak')
             {
                 $('.chatdiv').append(data.speaker_uid+"说:"+data.speaker_msg+"<br>");
             }

             if(data.type=='join')
             {
                 $('.chatdiv').append("新用户ID:"+data.new_uid+"加入了聊天室<br>");
             }

             if(data.type=='exit')
             {
                 $('.chatdiv').append("用户ID:"+data.uid+"离线<br>");
             }
         }

         /**
          * 按钮发送
          */
         this.sendMessage=function()
         {
             $('#send').click(function (event) {
                 var sendmsg={'type':'speak',"msg":$('#msg').val()};
                 this.ws.send(JSON.stringify(sendmsg));//
                 console.log("本地:数据发送->"+sendmsg);
                 $('.chatdiv').append(+"我说:"+$('#msg').val()+"<br>");//同时
             }.bind(this));
         }


         /**
          *
          * @returns {string}
          */
         this.wsStatus=function ()
         {
             status = ['未连接','连接成功,可通讯','正在关闭','连接已关闭或无法打开'];
             if(this.ws.readyState==1){
                 return true;
             }
             return false;
             //return status[this.ws.readyState]+'->code:'+ws.readyState;
         }


         /**
          * 按钮状态
          */
         this.sendBtnStatus=function ()
         {
             if(this.wsStatus()){
                 $('#send').html('发送信息');
                 $('#send').removeClass('layui-btn-primary');
             }else{
                 $('#send').html('已经离线');
                 $('#send').addClass('layui-btn-primary');
             }
         }


    }

    $(document).ready(function () {
        var conn=new websocket();
        conn.init();
        setInterval(function (){
            conn.sendBtnStatus()
        },1000);
    });
</script>
<script>

</script>
</body>
</html>





[隐藏样式|查看源码]


『回复列表(6|隐藏机器人聊天)』

1.
9c66534ae633e669587ad078b25c7b50211014.png
(/@Ta/2019-05-09 14:12//)

2.
用户被禁言,发言自动屏蔽。
(/@Ta/2019-05-09 14:44//
被禁言
)

3. 如果需要定时任务,可以添加下面的代码。
composer安装 Timer

在进程启动函数里,添加定时事件

    /**
     * 每个进程启动
     * @param $worker
     */
    public function onWorkerStart($worker)
    {

        echo  '进程启动>>>>>>>>>>>>>>>>>>>>>>>>>'."\n";
        Timer::add(0.1, array($this, 'radioInterval'), null, true);
        return;
    }



然后调方法
    /**
     * 定时任务回调函数,比如用来定时广播
     */
    public function radioInterval()
    {
        $msg='北京时间:'.date("Y-m-d H:i:s");
        echo '定时广播发送:'.$msg."\n";
        $this->radio($this->AopReturn(['type'=>'radio','msg'=>$msg]));
    }
(/@Ta/2019-05-09 14:38//)

5. 暖贴
(/@Ta/2019-05-09 17:49//)

6. 《高性能Javascript》一书即指出:警告:关于JSON和eval需要注意的是:在代码中使用eval是很危险的,特别是用它执行第三方的JSON数据(其中可能包含恶意代码)时,尽可能使用JSON.parse()方法解析字符串本身。该方法可以捕捉JSON中的语法错误,并允许你传入一个函数,用来过滤或转换解析结果。如果此方法以备Firfox 3.5 、IE8 及 Safari 4 原生支持。大多数javascript类库包含的JSON解析代码会直接调用原生版本,如果没有原生支持的话,会调用一个略微不那么强大的非原生版本来处理。
(/@Ta/2019-05-16 08:53//)

7.

tp和layui还真是好基友啊
小米5黑色低配版

(/@Ta/2019-05-16 09:53//)

回复需要登录

7月6日 00:00 星期天

本站由hu60wap6驱动

备案号: 京ICP备18041936号-1