服务器文件上传后,客户端下载-webscoket一对一

主要端末:小程序 云服务器 客户端A 客户端B 客户端C

流程:

1.小程序用户将文件通过小程序上传至云服务器,同时发送一个websocket,内部端口

2.云服务器与客户端ABC建立webscoket连接

3.当小程序用户需要上传到指定的客户端A电脑上的时候,我们通过webscoket只针对客户端A发送指令,让客户端A去下载

4.下载完成后,要么在客户端通过ajax+curl更新数据库,要么通过webscoket的回调函数+curl更新数据库。

完毕!

html代码:

html 复制代码
<!DOCTYPE html>
<html lang="en">
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <title>Title</title>
</head>
<body>
<div id="content">

</div>
</body>
<script type="text/javascript" src="/static/jquery.min.js"></script>
<script>
    let lockReconnect = false; //避免ws重复连接
    let ws = null; // 判断当前浏览器是否支持WebSocket
    let wsUrl = "ws://0.0.0.125:1234";
    let printer_id 
    createWebSocket(wsUrl); //连接ws
    function contentLog(msg){
        let pLength = $("#content").find("p").length;
        if (pLength>=300){
            $("#content").html("");
        }
        $("#content").append("<p>"+msg+"</p>")

    }
    function createWebSocket(url) {
        try {
            if ('WebSocket' in window) {
                ws = new WebSocket(url);
            }
            initEventHandle();
        } catch (e) {
            reconnect(url);
            contentLog(e)
        }
    }


    function initEventHandle() {
        ws.onclose = function() {
            reconnect(wsUrl);
            contentLog(printer_id+"文件连接关闭!" + new Date().toLocaleString())
        };
        ws.onerror = function() {
            reconnect(wsUrl);
            contentLog(printer_id+"文件连接错误!" + new Date().toLocaleString())
        };
        ws.onopen = function() {
            let msg = {'uid':printer_id};
            ws.send(JSON.stringify(msg));
            heartCheck.reset().start(); //心跳检测重置
            contentLog(printer_id+"文件连接成功!" + new Date().toLocaleString())
        };
        ws.onmessage = function(event) { //如果获取到消息,心跳检测重置
            heartCheck.reset().start(); //拿到任何消息都说明当前连接是正常的
            if (event.data != 'pong') {
                contentLog("有下载文件!" + new Date().toLocaleString())
                let data = JSON.parse(event.data);
                $.ajax({
                    url:"{:url('index/downloadFile')}",
                    data:data,
                    type:"post",
                    success:function (ev){
                        contentLog(ev)
                                          }
                });
            }
        };
    }
    // 监听窗口关闭事件,当窗口关闭时,主动去关闭websocket连接,防止连接还没断开就关闭窗口,server端会抛异常。
    window.onbeforeunload = function() {
        ws.close();
    }
    function reconnect(url) {
        if (lockReconnect) return;
        lockReconnect = true;
        setTimeout(function() { //没连接上会一直重连,设置延迟避免请求过多
            createWebSocket(url);
            lockReconnect = false;
        }, 2000);
    }

    //心跳检测
    let heartCheck = {
        timeout: 60000, //60秒发一次心跳
        timeoutObj: null,
        serverTimeoutObj: null,
        reset: function() {
            clearTimeout(this.timeoutObj);
            clearTimeout(this.serverTimeoutObj);
            return this;
        },
        start: function() {
            let self = this;
            this.timeoutObj = setTimeout(function() {
                //这里发送一个心跳,后端收到后,返回一个心跳消息,
                //onmessage拿到返回的心跳就说明连接正常
                ws.send("ping");
                contentLog("心跳测试");
                self.serverTimeoutObj = setTimeout(function() { //如果超过一定时间还没重置,说明后端主动断开了
                    ws.close(); //如果onclose会执行reconnect,我们执行ws.close()就行了.如果直接执行reconnect 会触发onclose导致重连两次
                }, self.timeout)
            }, this.timeout)
        }
    }

</script>

</html>

workerman代码:

html 复制代码
<?php
use Workerman\Worker;
use Workerman\Connection\TcpConnection;
require_once __DIR__ . '/vendor/autoload.php';

// 初始化一个worker容器,监听1234端口
$worker = new Worker('websocket://0.0.0.0:1236');

/*
 * 注意这里进程数必须设置为1
 */
$worker->count = 1;
// worker进程启动后创建一个text Worker以便打开一个内部通讯端口
$worker->onWorkerStart = function($worker)
{
    // 开启一个内部端口,方便内部系统推送数据,Text协议格式 文本+换行符
    $inner_text_worker = new Worker('text://127.0.0.1:5679');
    $inner_text_worker->onMessage = function(TcpConnection $connection, $buffer)
    {
        // $data数组格式,里面有uid,表示向那个uid的页面推送数据
        $data = json_decode($buffer, true);
        $uid = $data['uid'];
        // 通过workerman,向uid的页面推送数据
//        $ret = broadcast($buffer);
        $ret = sendMessageByUid($uid, $buffer);
        // 返回推送结果
        $connection->send($ret ? 'ok' : 'fail');
    };
    // ## 执行监听 ##
    $inner_text_worker->listen();
};
// 新增加一个属性,用来保存uid到connection的映射
$worker->uidConnections = array();
// 当有客户端发来消息时执行的回调函数
$worker->onMessage = function(TcpConnection $connection, $data)
{
    global $worker;
    $post = json_decode($data, true);
    if (isset($post['uid'])) {
        // 判断当前客户端是否已经验证,既是否设置了uid
        if (!isset($worker->uidConnections[$post['uid']])) {
            // 没验证的话把第一个包当做uid(这里为了方便演示,没做真正的验证)
            $connection->uid = $post['uid'];
            /* 保存uid到connection的映射,这样可以方便的通过uid查找connection,
             * 实现针对特定uid推送数据
             */
            $worker->uidConnections[$connection->uid] = $connection;
            return;
        }
    }else{
        echo $data;
    }
};

// 当有客户端连接断开时
$worker->onClose = function(TcpConnection $connection)
{
    global $worker;
    if(isset($connection->uid))
    {
        // 连接断开时删除映射
        unset($worker->uidConnections[$connection->uid]);
    }

};

// 向所有验证的用户推送数据
function broadcast($message)
{
    global $worker;
    foreach($worker->connections as $connection)
    {
        $connection->send($message);
    }
    return true;
}

// 针对uid推送数据
function sendMessageByUid($uid, $message)
{
    global $worker;
    if(isset($worker->uidConnections[$uid]))
    {
        $connection = $worker->uidConnections[$uid];
        $connection->send($message);
        return true;
    }
    return false;
}

// 运行所有的worker
Worker::runAll();
相关推荐
BingoGo16 小时前
OpenSwoole 26.2.0 发布:支持 PHP 8.5、io_uring 后端及协程调试改进
后端·php
JaguarJack16 小时前
OpenSwoole 26.2.0 发布:支持 PHP 8.5、io_uring 后端及协程调试改进
后端·php·服务端
JaguarJack2 天前
推荐 PHP 属性(Attributes) 简洁读取 API 扩展包
后端·php·服务端
BingoGo2 天前
推荐 PHP 属性(Attributes) 简洁读取 API 扩展包
php
JaguarJack3 天前
告别 Laravel 缓慢的 Blade!Livewire Blaze 来了,为你的 Laravel 性能提速
后端·php·laravel
郑州光合科技余经理3 天前
代码展示:PHP搭建海外版外卖系统源码解析
java·开发语言·前端·后端·系统架构·uni-app·php
QQ5110082853 天前
python+springboot+django/flask的校园资料分享系统
spring boot·python·django·flask·node.js·php
WeiXin_DZbishe3 天前
基于django在线音乐数据采集的设计与实现-计算机毕设 附源码 22647
javascript·spring boot·mysql·django·node.js·php·html5
longxiangam3 天前
Composer 私有仓库搭建
php·composer
小扎仙森3 天前
关于阿里云实时语音翻译-Gummy推送WebSocket
websocket·阿里云·云计算