laravel + swoole 开发及时聊天deom

2 篇文章 0 订阅
1 篇文章 0 订阅

环境说明:(Linux + centos + php + nginx + mysql + redis)

一、安装swoole扩展及redis

我用宝塔简单


 

二、服务端代码

因为Swoole只能运行在PHP CLI模式下,所以通过Laravel Command来实现

1.生成Command类

项目根目录下执行:php artisan make:command SwooleServer

2.编写webSocket Server逻辑

SwooleServer.php

<?php

namespace App\Console\Commands;

use Illuminate\Console\Command;
use Illuminate\Support\Facades\Redis;
use Illuminate\Support\Facades\Request;

class SwooleServer extends Command
{
    /**
     * The name and signature of the console command.
     *
     * @var string
     */
    protected $signature = 'command:swoole_test';

    /**
     * The console command description.
     *
     * @var string
     */
    protected $description = 'Command description';

    /**
     * Create a new command instance.
     *
     * @return void
     */
    public function __construct()
    {
        parent::__construct();
    }

    /**
     * Execute the console command.
     *
     * @return mixed
     */
    public function handle()
    {
        //创建server
        $server = new \Swoole\WebSocket\Server("0.0.0.0",9502);

        //监听连接进入事件
        $server->on('Connect', function ($server, $fd) {
            $userid = Request::input('userid');
            echo "Client: Connect456-$userid.\n";
        });

        //连接成功回调
        $server->on('open', function (\Swoole\WebSocket\Server $server, $request) {
            $this->info($request->fd . '链接成功');
            $userid = Request::input('userid');
            echo "Client: Connect-$userid.\n";
        });

        //收到消息回调
        $server->on('message', function (\Swoole\WebSocket\Server $server, $frame) {
            $this->info($frame->data . 'msg');
            $msg = json_decode($frame->data,true);

            $fd = $frame->fd;
            if(isset($msg['type'])){
                $type = $msg['type'];
                if($type == 1){
                    //绑定用户信息和fd信息
                    $from_userid = $msg['from_userid'];
                    $cacheKey = "socket_user:id_".$from_userid;
                    $cacheFdKey = "socket_fd:id_".$fd;
                    $time = 86400;
                    $data = [
                        'userid' => $from_userid,
                        'fd' => $fd
                    ];
                    Redis::setex($cacheKey,$time,json_encode($data));
                    Redis::setex($cacheFdKey,$time,json_encode($data));
                    $to_userinfo = Redis::get($cacheKey);
                    if($to_userinfo){

                        $server->push($fd,$from_userid.'连接成功,可以开始聊天啦');

                    }else{
                        $server->push($fd,$fd.'连接失败');
                    }


                }else if($type == 2){
                    //发送消息
                    $content = $msg['data'];
                    $from_userid = $msg['from_userid'];
                    $this->info($from_userid . 'msg');
                    $to_userids = $msg['to_userids'];//1,2,3
                    $to_userids_arr = explode(',',$to_userids);
                    foreach ($to_userids_arr as $k => $v){
                        $cacheKey = "socket_user:id_".$v;
                        $to_userinfo = Redis::get($cacheKey);
                        $to_userinfo = json_decode($to_userinfo,true);
                        if(!$to_userinfo){
                            $this->info($content.'对方不在线');
                            $server->push($frame->fd,$to_userinfo['userid'].'对方不在线');
                        }else{
                            $this->info($content.'对方在线');
                            $to_fd = $to_userinfo['fd'];

                            //推送信息给指定用户
                            $server->push($to_fd,$content);
                        }
                    }



                }else if($type == 3){
                    //发送心跳包
                    $this->info('心跳包');
                }

            }else{
                //连接失败
                $server->push($frame->fd,'连接失败,退出重进');
            }

        });

        //关闭链接回调
        $server->on('close', function ($ser, $fd) {
            //断开连接删除用户在线状态
            $cache = Redis::get("socket_fd:id_".$fd);
            $caches = json_encode($cache,true);
            $cacheKey = "socket_user:id_".$caches['userid'];
            $cacheFdKey = "socket_fd:id_".$caches['fd'];
            Redis::del($cacheKey);
            Redis::del($cacheFdKey);
            $this->info($fd . '断开链接');

        });

        $server->start();
    }
}

3、服务器放行端口号 宝塔防火墙放行端口号

4、在项目根目录运行以下命令 启动服务 这样就开始监听该端口号了
php artisan command:swoole_test

三、客户端实现

index.blade.php

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
    <script src="http://code.jquery.com/jquery-1.9.1.js"></script>
</head>

<body>
<h3>demo 1</h3>
<div style="width:300px;margin:0 auto;border:1px solid #ccc;">
    <div id="content" style="overflow:auto;height:500px;"></div>
    <hr />
    <div style="height:130px;background:white;">
        发送人userid:<input type="text" class="form-control" id="from_userid"  placeholder="发送人id" value="{{$userid}}"></br></br>
        接收人userid:<input type="text" class="form-control" id="to_userids"  placeholder="接收人id"></br></br>
        发送内容:<input type="text" class="form-control" id="message"  placeholder="请输入内容"></br></br>
        <button type="button" class="btn btn-primary" onclick="sendMessage()">点击发送</button></br></br>
    </div>
</div>
</body>
</html>
<script type="text/javascript">
    var arr = {};

    if(window.WebSocket){
        //创建连接
        // 端口和ip地址对应不要写错
        // var webSocket = new WebSocket("ws://0.0.0.0:9501");
        //https请求
        // var wss = "wss://zsy.hzyxhfp.com/wss:9501";
        //http请求
        var wss = "ws://你的ip:9502";
        var webSocket = new WebSocket(wss);


        // 握手成功
        webSocket.onopen = function (event) {

            console.log('webSocket 链接成功');
            if (webSocket.readyState === 1) {
                var from_userid = document.getElementById('from_userid').value;
                var arr = {};
                arr['from_userid'] = from_userid;
                arr['type'] = 1;//1:第一次连接,绑定用户信息
                var arrJson =  JSON.stringify(arr);
                webSocket.send(arrJson);
                // console.log("connected readyState");
            }

        };

        //收到服务端消息回调
        webSocket.onmessage = function (event) {
            console.log(webSocket,'onmessage');
            var content = document.getElementById('content');
            content.innerHTML = content.innerHTML.concat('<p style="margin-left:20px;height:20px;line-height:20px;">'+event.data+'</p>');
        }

        //监听断开连接
        webSocket.onclose = function(event) {
            console.log(webSocket,'onclose');
            var content = document.getElementById('content');
            content.innerHTML = content.innerHTML.concat('<p style="margin-left:20px;height:20px;line-height:20px;">您已断开连接</p>');
            //重新连接
        }


        //发送消息
        var sendMessage = function(){
            var data = document.getElementById('message').value;
            arr['data'] = data;
            arr['from_userid'] = document.getElementById('from_userid').value;
            arr['to_userids'] = document.getElementById('to_userids').value;
            arr['type'] = 2;//2:发送信息

            var myJSON =  JSON.stringify(arr);
            console.log(webSocket);
            if (webSocket.readyState === 1) {
                //当前用户在线
                webSocket.send(myJSON);
                // webSocket.send(data);
                var content = document.getElementById('content');
                content.innerHTML = content.innerHTML.concat('<p style="margin-left:20px;height:20px;line-height:20px;color: blue;">'+data+'</p>');
            }else{
                //当前用户不在线
                console.log('连接失败,请刷新重进');

            }

        }


        //每隔5秒发送一个心跳包
        setInterval(function(){
            console.log('setInterval')
            var arr = {};
            arr['type'] = 3;
            var myJSON =  JSON.stringify(arr);
            webSocket.send(myJSON)
        },5000);



    }else{
        console.log("您的浏览器不支持WebSocket");
    }

</script>

四、随便写个路由访问

Route::get('/swoole_index','TestController@index');

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;

class TestController extends Controller
{

    public function index(Request $request){
        $user_id = $request->get('user_id');
        return view("index", ['userid'=>$user_id]);
    }

}

打开: 你的域名/swoole_index?user_id=1

 五、完成

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值