nodeJs socketJs 搭建长连接(2) 项目应用整合

今天我们在这里要说的是wehsocket和node开发长连接问题,我们在真正的项目中,可能要实现的功能不知是简单的聊天功能,我们现在要整合redis,rabbitMQ,等实现o2o的提醒功能:

首先,整合一次redis:

我们建立一个chat文件夹,在其中写入一个package.json文件,用于生成我们的node类库

{
  "name": "zefun",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "dependencies": {
    "apn": "^1.5.2",
    "amqp": "^0.2.4",
    "co": "^3.0.6",
    "co-redis": "^1.1.1",
    "log4js": "^0.6.28",
    "express": "^4.13.3",
    "redis": "^0.10.3",
    "redis-sentinel": "^0.1.3",
    "socket.io": "^1.3.7"
  },
  "devDependencies": {},
  "author": "",
  "license": "ISC"
}
这时,我们通过运行node的命令进行安装类库,npm install
安装结束后,我们会生成一个node_modules的文件,还要在本层的目录创建一个logs的文件夹,因为我们一会会使用一个日志系统进行输出,但是,node只有写文件的权限,没有输出文件夹的权限

新建一个redisClient.js,作为redis的客户端连接

var PORT = 6379;
var HOST = '120.25.254.164';
var redis = require('redis');
var chatClient = redis.createClient(PORT,HOST);
var logger = require("./log").logger("redis");
chatClient.on('error', function(err){
    logger.error(err);
});
var chat_sadd = function(key, field) {
    chatClient.sadd(key, field);
    logger.info("redis sadd --> key : " + key + ", field : " + field);
}
var chat_srem = function(key, field) {
    chatClient.srem(key, field);
    logger.info("redis srem --> key : " + key + ", field : " + field);
}
var chat_smembers = function(key) {
    return chatClient.smembers(key);
}
var chat_hset = function(key, userId, sockedId) {
    chatClient.hset(key, userId, sockedId);
    logger.info("redis hset --> key : " + key + ", field : " + userId + ", value :" + sockedId);

var chat_hget = function(key, userId) {
    return chatClient.hget(key, userId);

 
exports.chat_sadd = chat_sadd;
exports.chat_srem = chat_srem;
exports.chat_smembers = chat_smembers;
exports.chat_hset = chat_hset;
exports.chat_hget = chat_hget;
下面我们在主js中进行引用和传值即可

var co = require('co');
var wrapper = require('co-redis');
var redis = wrapper(require("./redisClient"));
我们看到上面我们使用了一个叫co的类库,并使用wrapper对redis进行了包装,只有经过包装,在操作redis的时候,才能处理了node中异步的程序,将redis取值变成了同步的方式,即取到值后才能进行下面程序的执行
co(function* () {
<span style="white-space:pre">    </span>var userSID = yield redis.chat_hget(USER_SOCKET_KEY, toUser);
    io.sockets.connected[userSID].emit('getMessage',{msg:msg});
})();
对于存值不需要这么同步
redis.chat_sadd(redis_key,data.userId);
redis就算是结束了,下面就开始rabbitMQ的搭建和操作:
此处我们将node作为了rabbit的一个client进行监听和处理程序,首先新建一个mqClient.js作为队列的客户端进行监听

conn.queue('queue_chat_notify', { autoDelete: false, durable: true }, function(queue) {
    queue.subscribe(function (msg) {
      receiveNotify(msg.data);
    });
  });
  exports.createConnection = function(r1, r2) {
    receiveLogout = r1;
    receiveNotify = r2;
  }
这是我们最核心的进行监听的程序,是要subscribe这个方法,就可以进行监听了,请注意receiveLogout这个方法,我们这个方式是需要在主js中作为参数传入的,当客户端进行传入一个方法作为替代方法的时候,就可以进行读取消息,但是如果没有传入,那么该条数据丢失.下面是主js中的代码
var mq = require("./mqClient");
mq.createConnection(receiveNotify);
//rabbitmq监听到通知的回调操作
var receiveNotify = function(msg) {
    logger.info("\r\n\r\n<-- receiveNotify begin -->");
    sendMsg(msg);
}
这样,在客户端中判定登陆后,启用该方法就可以读取队列中的消息,进行发送消息了,下面给出整个mqClient.js的全部内容
var amqp = require("amqp");
 
var exchName = "directExchange";
 
var connOptions = {
      host: '120.25.254.164',
      port: 5672,
      login: 'zefun',
      password: 'zefun'
    };
 
var exchOption = {
      type: 'direct',
      durable: true,
      autoDelete: false,
      confirm: false
    };
 
var conn;
var receiveNotify  = null;
var logger = require('./log').logger("rabbitmq");
conn = amqp.createConnection(connOptions);
 
conn.on('ready',function() {
  logger.info("rabbitmq is ready ... ");
  conn.queue('queue_chat_notify', { autoDelete: false, durable: true }, function(queue) {
    queue.subscribe(function (msg) {
      logger.info("queue_chat_notify consumer msg : " + msg);
      receiveNotify(msg.data);
    });
  });
});
 
conn.on('close', function(){
  logger.error("rabbitmq is close");
});
 
conn.on('error', function (error) {
  logger.error('Connection error : ' + error);
});
 
exports.createConnection = function(r1) {
  logger.info("createConnection r1 : " + r1);
  receiveNotify = r1;
}
exports.publish = function(routeKey, message) {
  conn.publish(routeKey, message);
 
};
下面就是我们最后一步,看一下servier.js中的内容了
var app = require('express')();
var http = require('http').Server(app);
var io = require('socket.io')(http);
 
app.get('/', function(req, res){
    res.send('<h1>Welcome Realtime Server</h1>');
});
 
http.listen(3000, function(){
    console.log('listening on *:3000');
});
 
var mq = require("./mqClient");
 
var co = require('co');
var wrapper = require('co-redis');
var redis = require("./redisClient");
var redisClient = wrapper(redis.chatClient);
 
var logger = require("./log").logger("server");
 
var STORE_USER_KEY = "store_to_chat_user_set_";
var USER_SOCKET_KEY = "chat_user_to_socket_hash";
 
//rabbitmq监听到通知的回调操作
var receiveNotify = function(msg) {
    logger.info("\r\n\r\n<-- receiveNotify begin -->");
    sendMsg(msg);
}
 
mq.createConnection(receiveNotify);
 
io.on('connection', function (socket) {
 
  io.sockets.emit('connect',{hello:'connection success'});
  socket.on('sendMsg', function (from,toUser,msg,msgType) {
     co(function* () {
         var userSID = yield redisClient.hget(USER_SOCKET_KEY, toUser);
         io.sockets.connected[userSID].emit('getMessage',{msg:msg});
     })(); 
  });
 
  socket.on('initUser',function(data){
     var redis_key = STORE_USER_KEY + data.storeId;
 
     //redis插入数据 
     redisClient.sadd(redis_key,data.userId);
     redisClient.hset(USER_SOCKET_KEY, data.userId, socket.id);
 
     logger.info('initUser --->> 门店 :' + data.storeId + ', 用户 : ' + data.userId);
  });
 
  socket.on('disconnect', function () {
      
  });
});
 
var sendMsg = function(obj){
    co(function* () {
         var socketId = yield redisClient.hget(USER_SOCKET_KEY, obj.toUser);
         logger.info("socketId : " + socketId);
         io.sockets.connected[socketId].emit("getMessage", obj);
    })(); 
}
下面,我们写一个客户端,其实就是一个jsp文件
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%
    String chatPath = request.getContextPath();
            String chatPasePath = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort()
                    + chatPath + "/";
%>
<script src="<%=chatPath%>/js/common/socket.io.js"></script>
<script type="text/javascript">
var userId = '${session_key_user_id}';
var storeId = '${session_key_store_id}';
var user = {"userId" : userId, "storeId" : storeId};
if(!isEmpty(userId)){
    var socket = io.connect('ws://localhost:3000');
    socket.on('connect', function(data) {
        //登录聊天室
        socket.emit('initUser', user);
        
        //接收消息
        socket.on('getMessage', function(data) {
            console.log("" + data);
            var fid = data.fid;
            //PC通知类处理
            if (fid == 2) {
                var type = data.data.type;
                //新预约
                if (type == 2) {
                    //播放语音
                    textToVoice(0, data.data.msg);
                }
            }
        });
    });
}
</script>
可以进行触发登陆,然后进行接收消息即可了.
记得在linux上启动的时候 , 使用 forever start server.js 命令进行启动,可作为守护进程,这样node就不会随着终端的关闭而down掉。。。

到此我们的整套就写完了,最后注意一下日志,如果我们想将现在的类库导入成为package.json的话,在文件夹中使用npm init,自动生成json文件,就可以进行移植 

给出一个该项目的下载链接地址 http://download.csdn.net/detail/u014201191/9303347

#特别注意:

在本案例中 io.sockets.connected[socket.id].emit("method",msg) 和 io.sockets.sockets[socket.id].emit("method",msg) 这两个方法都不可用,可以换成: io.to[socket.id].emit("method",msg) 触发传送事件了,好像是TM因为版本的问题。。。

原文:https://blog.csdn.net/u014201191/article/details/50059017 
 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值