实时刷新的论坛,帮忙测试一下,感谢,顺便谈 Ajax 往 WebSocket 的一种快速迁移办法 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
爱意满满的作品展示区。
cheshirecat
V2EX    分享创造

实时刷新的论坛,帮忙测试一下,感谢,顺便谈 Ajax 往 WebSocket 的一种快速迁移办法

  •  
  •   a href="/member/cheshirecat">cheshirecat
    cheshirecats 2012-08-28 14:35:40 +08:00 5010 次点击
    这是一个创建于 4798 天前的主题,其中的信息可能已经有所发展或是发生改变。
    纯测试。不要注册用户,进去直接说话。左边的主题列表实时刷新。

    http://geekav.com

    支持 Chrome / Firefox / Safari。

    =======================================

    先看 Ajax,假设我们会用 $.post 某字串 s 给 a.php,然后回调某函数 f ( )。

    换成 WebSocket 后,你先需要在服务器上运行一个独立的 WS server,假设开在 8080 端口上。

    这个 WS server 可以用任何办法做,node.js 之类都可以,我比较怕麻烦就还是用 php,可以用 Ratchet 给 php 加 WS 支持。

    未来所有 client 也连接到这个 WS server 上,然后可以方便地做双向通讯和广播。例如 client 端代码:

    $socket = new WebSocket('ws://xxx.xxx.xxx.xxx:8080');
    $socket.Onerror= function(e) {
    console.log('WebSocket error: ' + e.data);
    };
    $socket.Onopen= function(e) {
    };
    $socket.Onmessage= function(e) {
    $socket.send('client received the msg');
    console.log(e.data);
    };

    server 端代码,假设名字是 ws.php:

    class WS_SERVER implements MessageComponentInterface {
    protected $clients;

    public function __construct() {
    $this->clients = new \SplObjectStorage;
    }

    public function onOpen(ConnectionInterface $conn) {
    $this->clients->attach($conn);
    $conn->send('hello');
    }

    public function onClose(ConnectionInterface $conn) {
    $this->clients->detach($conn);
    }

    public function onError(ConnectionInterface $conn, \Exception $e) {
    $conn->close();
    }

    public function onMessage(ConnectionInterface $conn, $msg) {
    echo $msg;
    }
    }

    $server = IoServer::factory(new WsServer(new WS_SERVER()), 8080);
    $server->run();

    然后在 server 运行 php ws.php。

    这里有一个问题,原始的 php 代码怎么和这个 ws.php 通讯?例如我们怎么知道应该在什么时候把什么信息广播给所有 client?

    这个可以在服务器本机自连接一下,未来 scaling 可能也更好做。

    客户 == [Ajax] ==> a.php == [WS] ==> ws.php == [WS] ==> 客户

    或者也可以更彻底一点,把 Ajax 调用和所有逻辑都改成走 WS。

    客户 == [WS] ==> ws.php == [WS] ==> 客户

    还有一个问题是传 session。这个想了想可以用 ws 的路径解决。client 这样连接:$socket = new WebSocket('ws://xxx.xxx.xxx.xxx:8080/' + session_id()); 这里 session_id() 函数从 document.cookie 里面读出来 session id。

    然后 server 用 $mcache->get('memc.sess.key.'.substr($conn->WebSocket->request->getPath(), 1)) 就可以从 memcached 里面把对应的 session 数据读出来,再自己 parse 成 array。如果是用数据库存 session 可以照样做。

    下面看转换 Ajax 调用。client 上写三个全局变量:var $socket; var $socket_uid = 0; var $socket_callback = new Array();

    然后 client 上写一个

    function ws_post(post_msg, post_callback) {
    post_msg.id = $socket_uid;
    $socket.send(JSON.stringify(post_msg));
    $socket_callback[$socket_uid] = function(msg) {post_callback(msg)};
    $socket_uid++;
    }

    然后 server 上就可以处理并且把正确的东西返回去,并且同时通知所有 client:

    public function onMessage(ConnectionInterface $conn, $msg) {
    $msg = json_decode($msg, true);
    $conn->send($msg['id'].','.process($conn, $msg));
    foreach ($this->clients as $client) {
    if ($client != $conn) // 这个信息发给其他用户
    $client->send('-1,'.$conn->remoteAddress);
    }
    }

    然后 client 上可以正确地调用回调函数:

    $socket.Onmessage= function(e) {
    var x = e.data.indexOf(',');
    var n = e.data.substr(0, x);
    var d = e.data.substr(x+1);
    if (n == '-1')
    console.log('a guy from ' + d + ' sent a msg to server');
    else
    $socket_callback[n](d);
    };

    嗯,就是这样了。
    3 条回复    1970-01-01 08:00:00 +08:00
    cheshirecat
        1
    cheshirecat  
    OP
       2012-08-28 14:40:49 +08:00
    不行。时不时就 Error while sending QUERY packet 然后奔溃了... debug 中。
    linuz
        2
    linuz  
       2012-08-29 21:52:32 +08:00
    403 Forbidden
    forest520
        3
    forest520  
       2012-09-10 17:02:26 +08:00
    meteor是不是就是干这个的?
    .wwads-cn { border-radius: 3px !important; } .wwads-text { color: var(--link-color) !important; }
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     2635 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 23ms UTC 14:21 PVG 22:21 LAX 07:21 JFK 10:21
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86