php是最好的语言

利用swoole实现websocket聊天demo


我这里只有后端代码前端的html没有,调试可以利用在线websocket来调试


*想要看前后端效果可以去https://github.com/Johnson19900110/ChatRoom(改一下ip和端口就可以用了 亲测没毛病,感谢大佬的)

代码主要是参考上面这位大佬的,在此基础加了

1、心跳检测、

2、异常账号登陆判定、

3、redis、

4、点对点发送消息。

先把上面github这个大佬的看懂了 新加的几个功能代码就能看懂了


*一定要先把上面的看懂 再来看下面的代码 不然会懵逼

*php server.php直接在命令行运行就好了


新增

1、心跳检测:新增两个参数具体看文档

heartbeat_check_interval   heartbeat_idle_time

2、异常连接判定:就是在连接的时候让前端传一个token之类的过来 判断是否是异常连接,如果是直接断掉

//        if (!isset($request->get) || !isset($request->get['uid'])) {
//            $this->server->close($request->fd);
//            return false;
//        }

3、redis(和原生一样redis)

4、点对点发送消息:就是指定fd来push就好了

5、多房间聊天:可以利用redis之类存储对fd进行分组,就可以实现多房间聊天了

6、发送文件:可以客户端先把文件上传第三方平台(七牛云),然后发送文件链接


server.php代码

<?php
class chat{
    const HOST = '0.0.0.0';//ip地址 0.0.0.0代表接受所有ip的访问
    const PART = 9095;//端口号
    private $server = null;//单例存放websocket_server对象
    private $users = array();  //保存连接的用户,fd=>nickname的形式保存

    public function start(){
        $this->server = new swoole_websocket_server(self::HOST,self::PART);
        $this->server->set([
            'daemonize' => 0,
            'worker_num' => 4,
            'task_worker_num' => 10,
            'max_request' => 1000,
            'heartbeat_check_interval' => 60, //心跳检测 60秒检测一次 100秒 对方向服务器发消息 自动断开 会回调onClose
            'heartbeat_idle_time' => 1000, //心跳检测 60秒检测一次 100秒 对方向服务器发消息 自动断开 不会回调用onClose
        ]);

        $this->server->on("open",[$this,'onOpen']);
        $this->server->on("message",[$this,'onMessage']);
        $this->server->on("task",[$this,'onTask']);
        $this->server->on("finish",[$this,'onFinish']);
        $this->server->on("close",[$this,'onClose']);

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

    public function onOpen($server, $request){


        //判断是不是非法连接 也可以传递token来判断有没有登陆 此处必须带uid不然就会关闭连接 比如:ws://127.0.0.1:9095?uid=1
//        if (!isset($request->get) || !isset($request->get['uid'])) {
//            $this->server->close($request->fd);
//            return false;
//        }

        //连接redis (这里用的原生redis)
        $redis = $this->redisConnect();

        //存一些必要的数据进redis(这里只是测试redis 后面并没有用到)
        $redis->set($request->get['uid'],json_encode(["fd"=>$request->fd]));

        //给登陆的用户端发送一个连接成功的信息
        $server->push($request->fd, json_encode(['code' => 200, 'message' => "online suce $request->fd","type"=>1])); //1系统消息,2用户聊天
    }

    public function onMessage($server, $frame){
        $data = json_decode($frame->data);
        switch ($data->type) {
            case 'init':
            case 'INIT':
                $this->users[$frame->fd] = $data->message;
                $message = '欢迎' . $data->message . '加入了聊天室';
                $response = array(
                    'type' => 1,    // 1代表系统消息,2代表用户群聊天
                    'message' => $message
                );
                break;

            case 'chat':
            case 'CHAT':
                $message = $data->message;
                $response = array(
                    'type' => 2,    // 1代表系统消息,2代表用户群聊天
                    'username' => $this->users[$frame->fd],
                    'message' => $message
                );
                break;

            case 'to': //这里是点对点发送 ,这里的测试用websocket在线测试,思路就是指定fd就好了
            case 'TO':
                $message = $data->message;
                $response = array(
                    'type' => 3,    // 1代表系统消息,2代表用户群聊天 3代表点对点
                    'username' => $this->users[$frame->fd],
                    'message' => $message,
                    'to' => $data->fd,
                );
                break;
            default:
                return false;
        }

        $this->server->task($response);
    }

    public function onTask($server, $task_id, $from_id, $message)
    {
        if ($message["type"] == 3){ //这里是点对点发送 ,这里的测试用websocket在线测试,思路就是指定fd就好了
            $this->server->push($message["to"], json_encode($message));
        }
        else{
            foreach ($this->server->connections as $fd){
                $this->server->push($fd, json_encode($message));
            }
        }


    }

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


    }

    public function onClose($server, $fd)
    {
        $username = $this->users[$fd];

        unset($this->users[$fd]);

        if( $username ) {
            $response = array(
                'type' => 1,    // 1代表系统消息,2代表用户聊天
                'message' => $username . '离开了聊天室'
            );
            $this->server->task($response);
        }

    }

    public function redisConnect()
    {
        $redis = new Redis();
        $redis->connect("192.168.1.222", "6379");
        $redis->auth("axt1314");
        $redis->select(2);
        return $redis;
    }
}

$ws = new chat();
$ws->start();


作者:xTao 分类:LNMP 浏览:2546 评论:0