swoole实现的一个简单聊天室功能

今天心血来潮花了点时间查看了一下swoole官方文档,写了一个websocket服务 思路大概就是利用swoole的广播从而实现一个聊天室功能

关键代码

     // $server->connections 遍历所有websocket连接用户的fd,给所有用户推送
    foreach ($ws->connections as $fd) {
        // 需要先判断是否是正确的websocket连接,否则有可能会push失败
        if ($ws->isEstablished($fd)) {
            $ws->push($fd, json_encode($msg, JSON_UNESCAPED_UNICODE));
        }
    }

主要就是监听message,当有客户端发送消息后, 通过connections获取所有的websocket用户,然后foreach循环推送新消息给所有客户端,达到广播效果 然后利用swoole table存储用户的昵称,在广播时将用户昵称一并返回给客户端

效果图

lazy-md-syntax

项目地址

laravel安装tideways

因为本人开发环境采用docker,所以这里也是采用docker安装.如果用源码安装请自行下载源码包编译php扩展

安装tideways扩展

    # 源码包地址
    wget https://github.com/tideways/php-xhprof-extension/archive/v4.1.6.tar.gz
    
    # docker构建 本人已打包好镜像,内含nginx+php-fpm 直接pull即可
    docker pull jianyl/nginx-php-fpm
    docker run -d -p 8080:80 -v /data/wwwroot:/var/www/html -v xxx:/etc/nginx/sites-enabled/ jianyl/nginx-php-fpm

注意: 如需自行构建dockerfile安装tideways扩展请参照以下代码

安装mongo

    docker run -p 27018:27017 --name=tideways-db -v tideways-db:/data/db -d mongo
    
    docker exec -it tideways-db bash
    $ mongo
    > use xhprof
    > db.results.ensureIndex( { 'meta.SERVER.REQUEST_TIME' : -1 } )
    > db.results.ensureIndex( { 'profile.main().wt' : -1 } )
    > db.results.ensureIndex( { 'profile.main().mu' : -1 } )
    > db.results.ensureIndex( { 'profile.main().cpu' : -1 } )
    > db.results.ensureIndex( { 'meta.url' : 1 } )

安装xhgui

    // 进入刚刚运行的nginx+php-fpm容器
    docker exec -it xxx bash 
    cd /var/www/html
    git clone https://github.com/laynefyc/xhgui-branch.git
    cd xhgui-branch
    php install.php
    
    # 修改配置文件
    vi xhgui-branch/config/config.default.php
    
    # 这里需要特别注意,因为本人安装的是v4.1.6版本,如果安装的是v5版本需改为'tideways_xhprof'
    'extension' => 'tideways',
    
    'save.handler' => 'mongodb',
    
    'db.host' => 'mongodb://172.19.0.1:27018',
    'db.db' => 'xhprof',

nginx配置

    # 项目nginx配置添加PHP_VALUE,告诉PHP程序在执行前要调用服务:
    location ~ \.php$ {
        # tideways 扩展
        fastcgi_param PHP_VALUE "auto_prepend_file=/var/www/xhgui-branch/external/header.php";
        ......
        ......
        ......
    }
    
    # xhgui前端展示页面配置 指向安装的xhgui的webroot目录
    server {
        listen   80; ## listen for ipv4; this line is default and implied
        
        root /var/www/xhgui-branch/webroot;
        index index.php index.html index.htm;
        server_name tideways.demo.com;
        
        sendfile off;
        
        error_log /dev/stdout info;
        access_log /dev/stdout;
        
        location / {
            index  index.php;
            if (!-e $request_filename) {
                rewrite . /index.php last;
            }
        }
        
        location ~ \.php$ {
            try_files $uri =404;
            fastcgi_split_path_info ^(.+\.php)(/.+)$;
            fastcgi_pass unix:/var/run/php-fpm.sock;
            fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
            fastcgi_param SCRIPT_NAME $fastcgi_script_name;
            fastcgi_index index.php;
            include fastcgi_params;
        }
    }

此时打开浏览器输入tideways.demo.com:8080应该能看到相应的效果

docker搭建nginx+php-fpm环境

关于docker的安装和基本常用命令请读者自行google,本文不做阐述 本次示例所用的系统和docker版本

  • centos7.5
  • Docker version 1.13.1

php搭建

    # 拉取镜像
    docker pull php:7.2-fpm-alpine
    docker run -d --name=php -v /data/wwwroot:/var/www/html php:7.2-fpm-alpine 

注意:-v是挂载文件 -v 主机目录:容器目录 /data/wwwroot目录为当前作者主机的目录,读者请自行创建网站目录

nginx搭建

    # 拉取镜像
    docker pull nginx:alpine
    
    # 创建nginx配置文件目录
    mkdir -p /data/nginx/conf.d
    
    # 运行临时容器
    docker run -d --name=nginx-conf nginx:alpine
    
    # 把nginx默认配置文件复制到宿主机,这样做的目的是为了有些人不会写nginx配置
    docker cp nginx-conf:/etc/nginx/conf.d/default.conf /data/nginx/conf.d/
    
    # 停止临时容器
    docker stop nginx-conf
    
    # 删除临时容器
    docker rm nginx-conf
    
    # 运行nginx容器把网站目录和配置文件挂载到容器内部
    docker run -d --name=nginx -p 8080:80 -v /data/wwwroot:/usr/share/nginx/html -v /data/nginx/conf.d:/etc/nginx/conf.d --link php nginx:alpine
    
    # 此时打开浏览器输入ip:8080应该就能看到nginx已经搭建成功
    echo '<h1>hello world!</h1>' > /data/wwwroot/index.html

注意:-v是挂载文件 -v 主机目录:容器目录 /data/wwwroot目录为当前作者主机的目录,读者请自行创建网站目录

修改nginx配置

    # 打开以下注释并修改配置
    vi /data/nginx/conf.d/default.conf
    
    location / {
        root   /usr/share/nginx/html;
        index  index.html index.htm index.php;
    }
    location ~ \.php$ {
        root           /usr/share/nginx/html;
        fastcgi_pass   php:9000;
        fastcgi_index  index.php;
        fastcgi_param  SCRIPT_FILENAME  /var/www/html/$fastcgi_script_name;
        include        fastcgi_params;
    }
    
    rm -rf /data/wwwroot/index.html
    echo '<?php phpinfo();' > /data/wwwroot/index.php
    
    # 重启nginx容器并打开浏览器输入ip:8080,此时应该能看到php相关信息如下图所示
    docker restart nginx

lazy-md-syntax

修改php版本

    docker stop php
    docker rm php
    
    # 拉取7.3镜像
    docker pull php:7.3-fpm-alpine
    
    # 运行php7.3容器并打开浏览器输入ip:8080,此时应该能看到php相关信息如下图所示
    docker run -d --name=php -v /data/wwwroot:/var/www/html php:7.3-fpm-alpine

lazy-md-syntax

概述

这个扩展包是针对阿里云消息队列AMQP(RabbitMQ)。通过简单的方法调用发送消费消息和接收消费消息。支持所有PHP的项目,本文针对Laravel作详细说明

安装

composer require jyil/aliwaremq

发布配置文件

php artisan vendor:publish --provider="Jyil\AliwareMQ\Laravel\Providers\LaravelServiceProvider" --force

注意:Laravel5.5- 自行添加providers

Jyil\AliwareMQ\Laravel\Providers\LaravelServiceProvider::class

配置

Key 描述
host 接入点
port 端口
virtualHost 资源隔离
accessKey 阿里云的accessKey
accessSecret 阿里云的accessSecret
resourceOwnerId 主账号id

生产者

app('aliwaremq')->send('queue', 'Hello World');

消费者

app('aliwaremq')->receive('queue');

属性配置

app('aliwaremq')->passive = false;
app('aliwaremq')->durable = true;
app('aliwaremq')->exclusive = false;
app('aliwaremq')->autoDelete = false;
app('aliwaremq')->noLocal = false;
app('aliwaremq')->noAck = false;
app('aliwaremq')->nowait = false;

匿名函数

app('aliwaremq')->receive($queue, '', function ($msgBody) {
    echo 'body---' . $msgBody;
});
  • 使用本扩展包前请对RabbitMQ有一定的了解

notadd jwt遇到的问题

因notadd框架PHP版本不再维护,现将原有架构逐一拆分为微服务,在重构用户注册模块遇到的jwt问题. 因原有注册登陆采用jwt认证,用laravel重写后发现新的token无法进行认证.

notadd jwt 配置

lazy-md-syntax

laravel jwt 配置

packagist tymon/jwt-auth lazy-md-syntax

经查看notadd源码,发现问题关键位置位于vendor/notadd/framework/src/JWTAuth/JWT.php line 278

lazy-md-syntax

如图所示,这段代码对比了prv是否一致,如果不一致则return false. 那这个prv是什么呢?查看jwt配置文件注释发现

/*
|--------------------------------------------------------------------------
| Lock Subject
|--------------------------------------------------------------------------
|
| This will determine whether a `prv` claim is automatically added to
| the token. The purpose of this is to ensure that if you have multiple
| authentication models e.g. `App\User` & `App\OtherPerson`, then we
| should prevent one authentication request from impersonating another,
| if 2 tokens happen to have the same id across the 2 different models.
|
| Under specific circumstances, you may want to disable this behaviour
| e.g. if you only have one authentication model, then you would save
| a little on token size.
|
*/

'lock_subject' => true,

这里详细指出了prv是一个身份验证模型,存放在载荷(Payload)里面,用于防止他人冒充.

lazy-md-syntax

经代码调试发现prv生成规则是采用sha1算法加密模型.而notadd的验证模型是Notadd\Foundation\Member\Member, laravel的验证模型为APP\User

目前博主采用的解决方案是通过设置载荷(Payload)把laravel的身份验证模型改为Notadd\Foundation\Member\Member

JWTAuth::claims(['prv' => sha1('Notadd\Foundation\Member\Member')]);

设置成功后生产token即可

\Auth::guard()->attempt($request->only(['name', 'password']));
$user = \Auth::guard()->user(); 
$token = JWTAuth::fromUser($user);   
  • 如有更好的方案望指出