Socket.io 和 Phalcon PHP

Posted

技术标签:

【中文标题】Socket.io 和 Phalcon PHP【英文标题】:Socket.io and Phalcon PHP 【发布时间】:2016-10-12 05:55:09 【问题描述】:

我正在使用Phalcon php,我想第一次尝试socket.io。我用socket.io做了教程聊天消息。但是现在我想在我的数据库中选择一些数据来使用查询 Phalcon 计算表“产品”中的行数:

$count_products = Product::count();

例如,在我的 html 页面中,我有 5 个产品,当我将一个或多个产品添加到我的产品表中时,我希望自动刷新以在我的 HTML 页面中查看 6 个产品。

你能帮我做吗?

【问题讨论】:

这不是一个答案,但我强烈建议使用专为套接字设计的工具,例如Node.js,它特别适合提供实时连接内容。在您的情况下,Phalcon 是 RESTful api 的最佳选择。 你的意思是我不应该使用 socket.io 但我必须使用 Node.js 来创建我的套接字并使用 Phalcon 服务器端来创建我的 Web 服务?我所有的网络服务都将被 Node js socket 消费? 不。使用 socket.io 后,您可以将它与 node.js 一起用作服务器端,它能够连接到 db 并提供您需要动态提供的数据。 Here 您可以在示例方法中找到进一步的解释。 好的,我明白你的意思了。但是我必须保留 phalcon 服务器端,因为这是一个非常好的 php 框架,他很快,我不能完全删除 phalcon,因为我所有的项目都是用他构建的。我可以在我的视图中实时使用 phalcon 服务器端并使用 socket io 吗?还是两者都用不好? 【参考方案1】:

一旦你在 ajax 请求上使用套接字,你应该保持你的 Phalcon 保持原样,并尝试使用 node.js+socket.io 实现简单的工具。

最简单的方法是在 Node 中创建一个事件转发器,它会在一侧监听事件,并将它们转发到用户浏览器。更多描述here。

在您的情况下,我建议在您的 Phalcon 模型中添加一个 afterSave 监听器,如 documentation 中所述。在afterSave 方法期间,您将能够通过例如。向您的 Node 服务发送一个 UDP 数据包,其中包含 X 表中有新记录的信息。

您的 Node 服务应该将此事件转发给客户端的浏览器,由 javascript 决定当前用户是否正在查看 X 表。如果是,它应该锁定视图以防止任何操作并向 Phalcon 服务发起 ajax 请求,该服务应该向您的数据库询问实际数据并刷新视图中的 HTML 内容。

当然,您可以创建一个 Node 服务,它可以直接在 DB 上侦听更改,并将适当的事件发送给适当的用户,所有内容都准备好完全动态更新。但这是一种先进的方法,可能有点矫枉过正。我想在这里强调一下,只要您的 Phalcon 服务针对速度进行了优化并且发送的数据不是太大,建议的解决方案就可以在几分之一秒内工作,给人一种实时的感觉。

当然,您可以使用 Phalcon 而不是 Node 创建转发服务,但时间长了您会后悔的,因为使用基于事件的工具来维护这种基于事件的脚本更容易。同样对于不时使用 JavaScript 的高级 PHP 程序员来说,快速学习这么一点点 Note.js 以做出如此简单的解决方案甚至都不是挑战。

使用 PHP 通过套接字发送包

$host = array(
    'scheme' => 'udp', // udp makes it lightweight and connectionless
    'host' => '192.168.10.10' // choose an IP where node is running
    'port' => '8888' // choose one > 1023
);
$param = sprintf('%s://%s:%s', $host['scheme'], $host['host'], $host['port']);
$socket = fsockopen($param, $errno, $errstr, $timeout);

我确实在Socket 类中包含了类似的内容。我宁愿使用持久套接字(pfsockopen),因此即使看起来不是这样,一次很少有进程会使用这个套接字。在afterSave 我使用Send 方法,或多或少:

fwrite($socket, json_encode($msg));

基于 websocket 的 Node.js 事件转发脚本

示例配置文件node.json:


    "wsServer": 
        "listeners": 
            "udp": 
                "port": 8888
            
        ,
        "server": 
            "port": 8000
        
    

您的依赖项将是 socket.iodgram。一旦你学会了如何创建 Node 应用程序,你稍后就会明白我的意思。

为了便于理解以下内容:

var config = require('node.json').wsServer;
var app = require('http').createServer().listen(config.server.port);
var io = require('socket.io').listen(app);
var listenerDgram = require('dgram').createSocket('udp4');
listenerDgram.bind(config.listeners.udp.port);

var users = ;

io.sockets.on('connection', function(socket) 
    // if you make user to connect by his individual ID during
    // websocket connection, providen after ?, like ?1234
    var user = parseInt(socket.handshake.query.user);

    // here to save user into var users
    if (!users[user]) 
        users[user] = 
            sockets: [socket]
        ;
     else 
        users[user].sockets.push(socket);
    

    socket.on('disconnect', function() 
        // removing user from var users
        // warning: socket by socket, and if last
        //   socket is closed, remove whole user section
    );

);

// to emit data to all sockets of choosen users
emit = function(sockets, message, data) 
    for (var x in sockets) 
        if (sockets[x]) 
            sockets[x].emit(message, data);
        
    
;

// now UDP listening section
listenerDgram.on('message', function(msg, rinfo) 

    // you can declare checkIncoming if you have standarized
    // frames, or just use msg as it is
    var _dat = checkIncoming(msg.toString().trim(), true);
    var _response = 
        action: _dat.action,
        data: _dat.data
    ;

    // you can declare standarizeFrame to define your own protocol,
    // or just use _response.
    var frame = standarizeFrame(_response);

    if (_dat.user)  // emitting to single user declared
        emit(users[_dat.user].sockets, 'notification', frame);
     else  // emitting to all connected users
        io.emit('notification', frame);
    
);

因此,您将 JSON 化的字符串发送到 Node 在端口 8888 上运行的服务器,并且用户 Web 界面连接到端口 8000 上的同一主机以接收它们。大量的调试工作摆在您面前。

PS:很抱歉这么武断的回答,但我自己走过它,因为我爱上了 Phalcon 并且不知道 Node.js 是否存在。给自己时间学习 Node 帮助我将基于事件的解决方案减少到绝对最低限度,将它们包含在 100 行而不是数千行中,使它们易于维护,让我的服务器深呼吸 CPU 和比基于 php 的客户端更满意.

【讨论】:

非常感谢您的回答。所以我会尝试用afterSave来实现你的方法。这似乎是最好的方法,它比 SQL 查询上的无限循环要好:)。 但是您能告诉我如何从 afterSave 向节点 js 发送消息吗? 这里有更多信息。希望现在就足够了。 哇,非常感谢,这真的很好,我会试试的。因此,在您的 sn-p 中使用 ratchet 或elephant.io 是没有用的:)

以上是关于Socket.io 和 Phalcon PHP的主要内容,如果未能解决你的问题,请参考以下文章

socket.io 中 io.on 和 socket.on 的区别

学习 Socket.io

expressJS 和 socket.io 监听不同的端口和 socket.io 客户端连接

phpstorm提示phalcon语法

engine.io 和 socket.io 有啥区别?

带有express和socket.io的节点js-找不到socket.io.js