前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >PHP系列 | PHP跨平台实时通讯框架 Socket.IO 的应用

PHP系列 | PHP跨平台实时通讯框架 Socket.IO 的应用

作者头像
Tinywan
发布2019-07-23 16:10:15
3.6K0
发布2019-07-23 16:10:15
举报
文章被收录于专栏:开源技术小栈

PHPSocket.IO 是什么?

  1. PHPSocket.IO是PHP版本的Socket.IO服务端实现,基于workerman开发,用于替换node.js版本Socket.IO服务端。
  2. PHPSocket.IO底层采用websocket协议通讯,如果客户端不支持websocket协议, 则会自动采用http长轮询的方式通讯。
  3. PHPSocket.IO实现的Polling通信机制包括Adobe Flash Socket、AJAX长轮询、JSONP轮询等。具体采用哪种机制通讯对于开发者完全透明, 开发者使用的是统一的接口。

设计的目标

利用PHP构建能够在不同浏览器和移动设备上良好运行的实时应用,如实时分析系统、在线聊天室、在线客服系统、评论系统、WebIM等。

PHPSocket.IO与workerman的区别是:

PHPSocket.IO基于workerman开发,workerman有的特性PHPSocket.IO都支持。PHPSocket.IO最大的优势是对各种浏览器的兼容性更好。

文档&&安装

文档仓库:https://github.com/walkor/phpsocket.io 使用composer安装

代码语言:javascript
复制
composer require workerman/phpsocket.io

应用案例

Nginx 主机配置
代码语言:javascript
复制
server {
    listen 443 ssl http2;
    server_name www.tinywan.com;
    ssl_certificate letsencrypt/iot.tinywan.com/full_chain.pem;
    ssl_certificate_key letsencrypt/iot.tinywan.com/private.key;
    set $root_path /var/www/iot.tinywan.com/public;
    root $root_path;
    more_set_headers "X-Frame-Options: SAMEORIGIN";

    location / {
        if (!-e $request_filename) {
            rewrite ^(.*)$  /index.php?s=/$1  last;
            break;
        }
    }

    # SocketIO 配置
    location /socket.io {
        proxy_pass http://127.0.0.1:2120;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "Upgrade";
        proxy_set_header X-Real-IP $remote_addr;
    }
}
服务端完整代码
代码语言:javascript
复制
<?php
namespace app\http\controller;

use PHPSocketIO\SocketIO;
use think\facade\Log;
use Workerman\Worker;

class Server
{
    /**
     * @author: Tinywan(Shaobo Wan)
     * @time: 2019/4/22 19:51
     */
    public function server()
    {
        // 全局数组保存uid在线数据
        $uidConnectionMap = array();
        // 记录最后一次广播的在线用户数
        $last_online_count = 0;
        // 记录最后一次广播的在线页面数
        $last_online_page_count = 0;
        // PHPSocketIO服务
        $sender_io = new SocketIO(2120);
        // 客户端发起连接事件时,设置连接socket的各种事件回调
        $sender_io->on('connection', function ($socket) {
            Log::info('客户端发起连接事件 ');
            // 当客户端断开连接是触发(一般是关闭网页或者跳转刷新导致)
            $socket->on('login', function ($uid) use ($socket) {
                Log::info('客户端登录uid ' . $uid);
                global $uidConnectionMap, $last_online_count, $last_online_page_count;
                // 已经登录过了
                if (isset($socket->uid)) {
                    return;
                }
                // 更新对应uid的在线数据
                $uid = (string)$uid;
                if (!isset($uidConnectionMap[$uid])) {
                    $uidConnectionMap[$uid] = 0;
                }
                // 这个uid有++$uidConnectionMap[$uid]个socket连接
                ++$uidConnectionMap[$uid];
                // 将这个连接加入到uid分组,方便针对uid推送数据
                $socket->join($uid);
                $socket->uid = $uid;
            });
            // 当客户端断开连接是触发(一般是关闭网页或者跳转刷新导致)
            $socket->on('disconnect', function () use ($socket) {
                Log::info('客户端断开 ' . json_encode($socket));
                if (!isset($socket->uid)) {
                    return;
                }
                global $uidConnectionMap, $sender_io;
                // 将uid的在线socket数减一
                if (--$uidConnectionMap[$socket->uid] <= 0) {
                    unset($uidConnectionMap[$socket->uid]);
                }
            });
        });
        // 当$sender_io启动后监听一个http端口,通过这个端口可以给任意uid或者所有uid推送数据
        $sender_io->on('workerStart', function () use ($sender_io) {
            // 监听一个http端口
            $inner_http_worker = new Worker('http://0.0.0.0:2121');//这里IP不用改变,用的内网通讯,端口不能与socket端口想通
            $inner_http_worker->onMessage = function ($http_connection, $data) use ($sender_io) {
                $postData = $data['post'];
                $to = $postData['to'] ?? '';
                Log::info('发送到用户to ' . json_encode($to));
                $content = htmlspecialchars($postData['content']);
                // 有指定uid则向uid所在socket组发送数据
                if ($to) {
                    $sender_io->to($to)->emit('new_msg', $content);
                } else {
                    // 否则向所有uid推送数据
                    $sender_io->emit('new_msg', $content);
                }
                // http接口返回,如果用户离线socket返回fail
                if ($to && !isset($uidConnectionMap[$to])) {
                    return $http_connection->send('offline');
                } else {
                    return $http_connection->send('ok');
                }
            };
            // 执行监听
            $inner_http_worker->listen();
        });
        Worker::runAll();
    }
}

1、启动服务端端: php web_msg.php start-d

代码语言:javascript
复制
$ php web_msg.php start -d
Workerman[web_msg.php] start in DAEMON mode
------------------------------------------- WORKERMAN -------------------------------------------
Workerman version:3.5.20          PHP version:7.2.9
-------------------------------------------- WORKERS --------------------------------------------
proto   user            worker          listen                     processes    status
tcp     www             PHPSocketIO     socketIO://0.0.0.0:2120    1             [OK]

2、发送消息

代码语言:javascript
复制
function send_web_msg($to_uid = 1, $content)
{
    if (empty($content)) {
        return ["error_code" => 404, "reason" => '缺少参数'];
    }
    $push_api_url = "http://127.0.0.1:2121/";
    $post_data = [
        "type" => "publish",
        "content" => $content,
        "to" => $to_uid
    ];
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, $push_api_url);
    curl_setopt($ch, CURLOPT_POST, 1);
    curl_setopt($ch, CURLOPT_HEADER, 0);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
    curl_setopt($ch, CURLOPT_POSTFIELDS, $post_data);
    curl_setopt($ch, CURLOPT_HTTPHEADER, array("Expect:"));
    $return = curl_exec($ch);
    curl_close($ch);
    return $return;
}

send_web_msg(1, "哈喽,Tinywan先生");
客户端完整代码

html 代码

代码语言:javascript
复制
<div><p id="notice-content" style="float: left">系统公告</p></div>

JS 代码

代码语言:javascript
复制
<script src='https://cdn.bootcss.com/socket.io/2.0.3/socket.io.js'></script>
<script src="https://cdn.bootcss.com/notify.js/3.0.0/notify.js"></script>
<script>
    $(document).ready(function () {
        $uid = "1";
        var socket = io("https://www.tinywan.com", { path: '/socket.io' });
        socket.on('connect', function () {
            console.log('连接成功');
            socket.emit('login', $uid);
        });
        socket.on('new_msg', function (msg) {
            console.log('系统消息:' + msg);
            $('#notice-content').html('系统提示:' + msg);
            $('.notification.sticky').notify();
        });
    });
</script>

效果图

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2019-07-22,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Tinywan的杂货摊 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • PHPSocket.IO 是什么?
  • 设计的目标
  • 文档&&安装
  • 应用案例
    • Nginx 主机配置
      • 服务端完整代码
        • 客户端完整代码
        • 效果图
        相关产品与服务
        腾讯企点客服
        腾讯企点客服(Tencent QiDian Customer Service)是为销售和客服提供多渠道商机转化与客户服务的智能客服平台。基于腾讯云的即时通讯、音视频、人工智能、大数据、云呼叫中心等技术,以个性化服务和精准客户洞察撬动销售转化与复购增购。企点客服全面覆盖了从销售到服务的全链路业务场景,帮助企业构建一体化的客户运营体系,极大提升了企业获客、待客、留客的效率。
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档