这篇文章上次修改于 3296 天前,可能其部分内容已经发生变化,如有疑问可询问作者。

1、需求

   做一个竞拍模块,需要在页面实时显示最新的竞拍价格

2、思路

   使用php的swoole提供的websocket可以很好的解决此需求

   1、进入页面,和服务端建立socket长链接

   2、链接成功,把返回的客户端标识id,当前业务id  发到sockets服务端,存在redis里面做关系映射

   3、当业务id有最新的竞拍出价时,从redis里面读取所有的socket客户端链接标识id,循环推送到客户端上

3、服务端代码示列

<?php
/**
 * swoole websocket 测试
 * 
 */
$redis = new Redis();
$redis->connect('127.0.0.1', 6379);
$redis->select(0);
$server = new swoole_websocket_server("0.0.0.0", 2345);
$server->set(array(
    'worker_num' => 4,    //worker process num
    'backlog' => 128,   //listen backlog
    'max_request' => 50,
    'dispatch_mode'=>1,
));
$server->on('Open', function ($server, $req) {
    echo "server: handshake success with fd{$req->fd}\n";
});
$globalServer = null;
$reqfd = null;
$server->on('Message',function( $serv, $frame ){
    global $server;    
    global $globalServer;
    $globalServer = $server;
    global $reqfd;
    $reqfd = $frame->fd;
    global $redis;    
    //web页面注册registerid    
    if(stripos($frame->data,'transId_') !== false){
        $transId = explode( '_', $frame->data );
        $fd = $redis->get('100_'.$transId[1] );
        if($fd != null){
            $fd = json_decode($fd,true);
        }
        $fd[$reqfd] = $reqfd;        
        $redis->set( '100_'.$transId[1], json_encode($fd) );
    }    
    //服务端请求更新数据,这里是websocket方式
    if(stripos($frame->data,'refresh_') !== false){
        $transId = explode( '_', $frame->data );
        $fd = $redis->get( '100_'.$transId[1] );
        if($fd != null){
            $fd = json_decode($fd,true);
        }        
        $err = 0;
        foreach( $fd as $f => $d ){
            $res = @$server->push( $f, 200 );
            if($res === false){
                unset($fd[$f]);
                $err++;
            }
        }        
        if($err){
            $fd = json_encode($fd);
            $redis->set( '100_'.$transId[1], $fd );
        }
    }
});
$server->on('Close', function ($server, $fd) {
    echo "connection close: " . $fd;
});
$server->start();

 

4、需要更新竞拍价格的客户端页面

<!--
To change this template, choose Tools | Templates
and open the template in the editor.
-->
<!DOCTYPE html>
<html>
    <head>
        <title>WebSocket 测试</title>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    </head>
    <body>
        <div>
            <h1>价格:</h1>
            <h3 id="money" >0</h3>
        </div>
    <script type="text/javascript">
        var ws = new WebSocket("ws://114.*.*.*:2345");
        ws.onopen = function ( evt ){
            ws.send( "transId_1" );    
        };        
        ws.onerror = function( evt ){
            console.log( '错误信息:' );
            console.log( evt );
        }        
        ws.onclose = function( evt ){
            console.log( '已关闭' );
        }        
        ws.onmessage = function(evt) {
            document.getElementById('money').textContent = evt.data;
            console.log( evt );
        }                
        window.onbeforeunload = function(){
            alert('确定关闭?');
        }
    </script>
    </body>
</html>

 

  5、通知页面更新测页面

<!--
To change this template, choose Tools | Templates
and open the template in the editor.
-->
<!DOCTYPE html>
<html>
    <head>
        <title></title>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    </head>
    <body>
        <div>发送消息</div>
    <script type="text/javascript">
        var ws = new WebSocket("ws://114.*.*.*:2345");
        ws.onopen = function ( evt ){
            console.log( evt );
            ws.send( "refresh_1" );
        };        
    </script>
    </body>
</html>