小程序 + PHP 使用 Swoole 实现实时聊天功能(Tp5框架)

4 篇文章 0 订阅
1 篇文章 0 订阅

配置

1,小程序域名必须是https

2,小程序的话证书必须要设置,因为是https的

(如果用的宝塔免费证书:证书路径是 /www/server/panel/vhost/ssl/站点名称/证书。如果前面路径跟我不一样的话必须找站点下面的那个证书,否则不能使呀)

3,阿里云安全组需要放行你用的端口(我开的是9501 - 9502),如果用的宝塔面板,宝塔上也需要在安全里面放行9501 - 9502端口

代码

1,放一下代码,tp5.1我在项目根目录放了一个这样文件(这样直接访问这个文件就可以运行服务了)

Socket.php(名字随便)

<?php

// [ 应用入口文件 ]
namespace think;

// 加载基础文件
require __DIR__ . '/../thinkphp/base.php';

// 支持事先使用静态方法设置Request对象和Config对象

// 绑定到index模块 执行应用并响应
Container::get('app')->bind('socket/Notice')->run()->send();

5,Server代码(注释都在里面):

app/socket/controller/Index.php

<?php
namespace app\Socket\controller;
use think\Db;

class Index
{
    private $server;
    private $redis;
    public function __construct()
    {
        // 创建服务,因为是小程序所以设置成,0.0.0.0 都可以访问的
        $this->server = new \swoole_websocket_server("0.0.0.0", 9502, SWOOLE_PROCESS, SWOOLE_SOCK_TCP | SWOOLE_SSL);
        // 小程序需要设置证书
        $this->server->set([
            'ssl_cert_file'=>'/www/xxxxxxxxxxx/fullchain.pem',
            'ssl_key_file'=>'/www/xxxxxxxxxxxxx/privkey.pem',
        ]);
        // 建立连接
        $this->server->on('Open', [$this, 'onOpen']);
        // 发送消息
        $this->server->on('Message', [$this, 'onMessage']);
        // 关闭连接
        $this->server->on('Close', [$this, 'onClose']);

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

    /**
     * 客户端连接
     * @param  [type] $server 服务端
     * @param  [type] $req    请求数据
     * @return [type]         [description]
     */
    public function onOpen($server, $req)
    {
        // 使用 redis 存一下客户端ID,用来推送消息
        // 可能有人要问为啥没有把实例化放在构造函数呢?
        //              这个构造函数只是在开启服务的时候执行一次,如果放在构造函数的话时间稍微长一点,下面使用redis就会出现断开的情况。
        //              不过可以改成redis长连接
        $this->redis->connect('127.0.0.1', 6379);

        // var_dump($req);
        // 让前端打开连接的时候存一个 用户ID => 客户端ID,这样就可以推送
        $id = $req->get['uid'];
        $this->redis->hSet('clientId', $id, $req->fd);

        echo "客户端:{$req->fd} 已连接 \n";
    }

    /**
     * 消息推送
     * @param  [type] $server 服务端
     * @param  [type] $frame  请求数据
     * @return [type]         [description]
     */
    public function onMessage($server, $frame)
    {
        // 数据解析成对象
        $data = json_decode($frame->data);
        
        // 内容名字和带哪些参数(比如:用户ID,对方的用户ID,头像,等等。。)是由前端决定的。最主要的就是自己的ID,对方的ID,和聊天内容
        var_dump($data);
        // uid => 用户ID
        // tid => 对方用户ID
        // cont => 聊天内容

        //  判断用户是否在聊天页面上:  在  :推送内容,并将内容加入数据库
        //                            不在:直接将内容加入数据库,设置未读
        $rr = $this->redis->hExists('clientId', $data->tid);
        if($rr) $server->push($this->redis->hGet('clientId', $data->tid), $frame->data);

        // 数据插入数据库
        $this->chatInsert($data);

        // 推送给自己
        $server->push($frame->fd, $frame->data);

        // 如果 A 和 B 在一个页面聊天,C 又给 A 发了一条消息,这样 A 和 B 的聊天列表里面,A 也会收到 C 发送的消息,因为 A 满足了'在线'的要求,所以在前端接收消息那里需要判断推送给自己的消息 tid 不等于 对方ID 的时候不显示,(uid == 自己登录的uid && tid == 对方的ID)  

        // 这样就知道只要你在聊天页面就能收到所有人的消息,就可以实现一个你在聊天的过程中,顶部弹出一个提示框 【孙某人给您发了一条消息】
    }

    /**
     * 客户端关闭
     * @param  [type] $server [description]
     * @param  [type] $fd     [description]
     * @return [type]         [description]
     */
    public function onClose($server, $fd)
    {
        // 删除 redis 用户的客户端ID,百度了一下 hash 不能通过值获取键名所以全部获取循环获取键名吧。
        $all = $this->redis->hGetAll('clientId');
        if($all)
        {
            foreach ($all as $k => $v) {
                if($v == $fd){
                    $this->redis->hDel('clientId', $k);
                    break;
                }
            }
        }

        echo "客户端:{$fd} 已关闭 \n";
    }

    /**
     * 聊天记录插入数据库,并且更新聊天列表最后一次聊天
     * @param [type] $data [description]
     */
    public function chatInsert($data)
    {
        // 插入聊天记录和聊天列表,逻辑用自己的吧
        // ——————————————————————————————————————————————————————
        // 放我一个例子。
        $time = time();
        // 插入聊天记录
        $insert = [
            'cl_uid'    => $data->uid,
            'cl_tid'    => $data->tid,
            'cl_cont'   => $data->cont,
            'cl_time'   => $time
        ];
        Db::name('chats_log')->insert($insert);

        // 插入聊天列表,更新最后一条消息用于显示在列表
        Db::name('msg_log')
            ->where("(ml_tid = $data->tid AND ml_uid = $data->uid) OR (ml_tid = $data->uid AND ml_uid = $data->tid)")
            ->update(['ml_cont' => $data->cont, 'ml_time' => $time]);

        // 
        // 比如用户表是 users,这样的联查就可以实现聊天列表了(users表里有用户头像,昵称,等等。。), 不过会有点慢
        // us_id 是用户ID(亲测能用)
        // $list = Db::name('msg_log')
        //     ->alias('a')
        //     ->join('users b', '(a.ml_uid <> 971 AND a.ml_uid = b.us_id) OR (a.ml_tid <> 971 AND a.ml_tid = b.us_id)')
        //     ->where('ml_uid', 971)
        //     ->whereOr('ml_pid', 971)
        //     ->select();

    }
}
// 启动服务器
$server = new Index();

  • 2
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
程序使用flash和ASP交互,使用access数据库保存聊天记录。需要的朋友可以下载到自己的网站目录使用; 演示地址:http://www.xyflash.com/myfile/chat/call.html 目前已经有以下功能: 2008-8-6 完成基本的程序界面和后台 2008-8-8 修改部分数据传送方式,稳定性进一步提高。并增加窗口抖动功能。 2008-8-10 增加聊天表情。 2008-8-11 新增加了公告,并优化了信息更新方式,程序应该可以更加的稳定。下一步准备增加聊天窗口背景和一些设置。 2008-9-23 增加聊天背景和音乐。下一步打算修改程序核心部分。提高消息发送速度,并解决聊天中可能出现的BUG 2008-9-29 核心代码全部重写,程序稳定性极大的提高,修复一些使用中的小问题,并增加查看聊天记录功能。 2008-9-30 修补一些可能被恶意攻击的漏洞,提高了程序的安全性。 2008-10-1 增加几个系统设置功能,方便大家根据不同的需要进行设置 2008-10-2 修改用户列表显示方式。 2008-10-3 增加聊天文字颜色设置。 2008-10-4 增加聊天文字字型字号设置。 2008-10-5 优化程序,解决了占用CPU过高的问题,程序运行极为流畅~ 2008-10-9 增加音乐播放器,修复新消息提醒出错的BUG,增加enter发送消息的选项 2008-10-10 新增私聊功能。方便用户进行不公开交谈。 2008-10-15 增加聊天类型选择 2008-10-15 实现聊天消息中包含的网址可以直接点击 2008-10-17 修改网页背景图片,美化聊天环境 2008-10-26 音乐播放器增加添加音乐功能 2008-10-27 重新修改音乐播放器外观 2008-10-28 实现聊天窗口拖放,修改表情为分页显示,提高显示速度。增加对话窗口抖动 2008-10-30 增加清屏功能,避免长时间聊天,对话窗口消息太多太耗资源

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值