使用nodejs+socket.io+redis订阅发布完成竞拍的过程

模拟用户竞拍出价的过程,其中涉及到soket.io实时消息以及拍单处理过程

具体的时序图业务流程整理如下:

使用nodejs+socket.io+redis订阅发布完成竞拍的过程_第1张图片


服务端nodejs代码: node socket_server.js

var RedisPort = 6379;
var RedisHost = "127.0.0.1";
var redis      = require("redis");
var rclient   = redis.createClient(RedisPort,RedisHost);
rclient.on("error", function (err) {
    console.log("Error(redis): " + err);
})

var io = require('socket.io').listen(8006);
var socketUsers = {};
io.sockets.on('connection', function(socket) {
    socket.emit('connect_success', {msg: socket.id});
    socket.on('login',function(data, fn){
        console.log("arrive here,login()"+data.order_id);
        socketUsers[socket.id] = {'order_id':data.order_id, 'socket':socket};

        //订阅
        rclient.subscribe("orderchannel:"+data.order_id); 
    });

    //收到消息后执行回调,message是redis发布的消息
    rclient.on('message', function(channel, price){
        console.log("我在频道【"+channel+"】接收到了消息:"+price);
        console.log(socketUsers);
        console.log("in message()\n");

        //channel名称:orderSubUsers:orderId
        var orderId = channel.substr(13);
        console.log("orderId=["+orderId+"]\n");

        console.log("aaaaaaa");
        var currSock = socketUsers[socket.id];
        console.log(currSock);
        for(var item in currSock) {
            if (item == 'order_id') {
                if(currSock[item] == orderId) {
                    socket.emit('receive', {'nowprice':price});
                }
            }
        }
        console.log("bbbbbbb");        
    });

    //监听断线
    socket.on('disconnect',function() {
        console.log('-链接断开['+socket.id+']-');   
        delete socketUsers[socket.id];
    });  
});


客户端php代码  bid_price.php





    
    
    测试nodejs socket.io的客户端    








fom提交后的代码: bid_operate.php

1,'username'=>'wangxiao','password'=>'secret'],
            ['id'=>2,'username'=>'shiyf','password'=>'secret'],['id'=>3,'username'=>'liming','password'=>'secret']);
    $username = trim(htmlentities($_POST['username']));
    $userpwd = trim(htmlentities($_POST['password']));
    $isSuccess = false;
    foreach($userList as $item) {
        if($username == $item['username'] && $userpwd == $item['password']) {
            $isSuccess = true;
            $_SESSION['username'] = $item['username'];
            $_SESSION['user_id'] = $item['id']; 
            header('Location:http://'.$_SERVER['HTTP_HOST'].'/bid_price.php');
        }
    }

    if (!$isSuccess) {
        echo "用户名或密码错误";
        return;
    }
}

function biddingCar() {
    //将出价信息写入数据库
    //考虑是从拍单主表和拍单出价表取最新价格合适?可以考虑在竞拍期间不写入最终价格,到竞拍结束的时候再写入价格。

    //先从redis中读取出该拍单的价格信息,拍单的信息从redis的集合中来找
    //判断价格是否合法:拍单的价格要比原来至少高出三百元
    //判断拍单状态

    $output = ['status'=>false, 'msg'=>''];

    $user_id  = $_SESSION['user_id'];
    $order_id = $_POST['order_id'];
    $price    = $_POST['price'];
    $socketId = $_POST['socketId'];
    $createtime = microtime(TRUE);


    //判断价格是否有变动 multi->watch()->exec();
    //判断拍单 然后监控拍单的价格如果价格有变化停止

    //todo:将用户的出价信息写入到bidding_log表
    //todo:将最新的价格写入到bidding_car表
    $redis = new Redis();
    $redis->connect('127.0.0.1', 6379);
    $watchKey = 'bidOrder:'.$order_id;
    $redis->watch($watchKey);

    $pdo = new PDO('mysql:host=192.168.3.125:3306;dbname=test','root','secret');
    try{
        $pdo->beginTransaction();
        //插入出价表
        $sth = $pdo->prepare('insert into order_bidding_log(order_id,user_id,price,createtime,status) values(?,?,?,?,1);');
        $result1 = $sth->execute([$order_id, $user_id, $price, $createtime]);

        $myinfo =  'in '.__METHOD__.',result1:'.var_export($result1,TRUE)."\n";
        file_put_contents('/tmp/shiyf.log', $myinfo, FILE_APPEND);

        if ($result1) {
            $sth = $pdo->prepare('update orders set user_id=?, price=? where id=?');
            $result2 = $sth->execute([$user_id, $price, $order_id]);//更改主表
            
            $myinfo =  'in '.__METHOD__.',result2:'.var_export($result2,TRUE)."\n";
            file_put_contents('/tmp/shiyf.log', $myinfo, FILE_APPEND);
            
            $ret = $redis->multi()->hset($watchKey,'price', $price)->hset($watchKey,'user_id',$user_id)->exec();

            $myinfo =  'in '.__METHOD__.',ret:'.var_export($ret,TRUE)."\n";
            file_put_contents('/tmp/shiyf.log', $myinfo, FILE_APPEND);

            if (is_array($ret)) {
                $count = count($ret);
                if ($ret[$count-1] === 0) {
                    $pdo->commit();
                    //将user_id与socketId关联起来
                    //$redis->sAdd('socketids:'.$user_id, $socketId);

                    //将user_id记录到一个订阅列表中,后续会查找其中的socketId,找到后会发消息
                    $redis->sAdd('orderSubUsers:'.$order_id, $socketId);

                    //发布消息
                    $redis->publish('orderchannel:'.$order_id, $price);

                    $output['status'] = true;
                } else {
                    $pdo->rollback();
                }
            } else {
                $pdo->rollback();
            }
        } else {
            $pdo->rollback();
            $output['msg'] = "插入order_bidding_log错误";
        }

        

    } catch(Exception $e) {
        $myinfo =  'in '.__METHOD__.','.$e->getMessage();
        file_put_contents('/tmp/shiyf.log', $myinfo, FILE_APPEND);
        $output['msg'] = "数据库操作异常:".$e->getMessage();
        $pdo->rollback();
    }

    echo json_encode($output);
    return;
    

}

    



?>

可以针对多个拍单进行出价,多个客户端会同时收到最新的出价信息的。

具体访问地址:127.0.0.1/bid_price.php?order_id=1001


你可能感兴趣的:(服务器,php,linux,nodejs)