在开发聊天室、直播、在线客服、监控、股票等在多客户端在线实时数据交互的应用中,如果客户端是自己写的,服务端可以使用aardio的HPSocket扩展库,如果客户端是各种厂商各种版本的浏览器,为了兼容各种低版本浏览器,则服务端可以考虑用aardio+node.js+socket.io模块(也可以只用node.js+socket.io,请根据项目需求、实际应用场景、开发者对语言和工具的熟悉程度选择合适的组合)。在socket.io的服务端里面,已经封装好了各种方法,可以方便地实现广播群聊(消息发到所有客户端)、组聊(消息发给指定群组的客户端)、私聊(精准发送到某个指定的客户端)功能。下面是我收集整理的一些演示例子(node.js源码),供大家参考:
io.sockets.on('connection', function (socket) { //这个socket就是发消息来的客户端对象
//回调函数的socket参数为一个 client
//与服务器的连接标示,不同的 client 会有不同的连接标示。
//第1种
//信息传输对象为当前 socket 对应的 client ,各个client socket 相互不影响。
//socket就是发消息来的客户端对象,用这个对象来发射,就是回复给发消息来的客户端
socket.emit ();
//第2种
//信息传输对象为所有 client ,排除当前socket 对应的 client
//socket就是发消息来的客户端对象,用这个对象加上broadcast来发射,就是群发给除此客户端外的其它所有客户端
socket.broadcast.emit
//第3种
//信息传输对象为所有 client
//io.sockets为服务端管理的所有客户端集合,用这个集合来发发射,就是用此列表里的每个客户端对象发送,即发给所有客户端
//io.sockets.emit()
//假设有两个聊天室,一个名为firefox,另一个为chrome
//第4种
//socket是发消息来的客户端对象,用join()方法让它订阅指定房间,可以订阅多个房间(相当于可以加入多个QQ群)
socket.join('firefox'); //如 socket.on('subscribe', function(data) { socket.join(data.room); })
socket.join('chrome');//如 io.on('connection', function(socket){ socket.join('some room'); });
socket.emit('subscribe',{"room" : "chrome"};//用subscribe指令也可以订阅指定房间
//socket是发消息来的客户端对象,用leave()方法让它取消订阅指定房间
socket.leave('firefox'); //如 socket.on('unsubscribe', function(data) { socket.join(data.room); })
socket.leave('chrome');
socket.emit('unsubscribe',{"room" : "chrome"};//用unsubscribe指令也可以取消订阅指定房间
//向名为chrome的房间里除发消息,排除发送方
socket.broadcast.to('chrome').emit('event_name', data);//event_name是事件名称,指令头
io.to('some room').emit('some event');//在房间里广播消息
io.in('some room').emit('some event');//在房间里广播消息
//向名为chrome的房间里所有客户端发送消息,包含发消息来的这个客户端
io.sockets.in('chrome').emit('event_name', data);//event_name是事件名称,指令头
//向指定socketid的客户端发送私聊消息,新版已经不用这种写法了
//io.sockets.socket(socketid).emit('message', 'for your eyes only');//
//私聊,socket是发消息来的客户端对象, socket.to(对方id).emit() 发消息给指定id的客户端
socket.on('say to someone', function(id, msg){
socket.broadcast.to(接收方的socket对象的id).emit('my message', msg);//加broadcast是排除发送方
});
});
还有一些是别人整理的,备用:
// 发送给当前客户端
socket.emit('hello', 'can you hear me?', 1, 2, 'abc');
// 发送给所有客户端,除了发送者
socket.broadcast.emit('broadcast', 'hello friends!');//加broadcast是排除发送方
// 发送给同在 'game' 房间的所有客户端,除了发送者 (不用broadcast也能排除发送者?)
socket.to('game').emit('nice game', "let's play a game");
// 发送给同在 'game1' 或 'game2' 房间的所有客户端,除了发送者 (不用broadcast也能排除发送者?)
socket.to('game1').to('game2').emit('nice game', "let's play a game (too)");
// 发送给同在 'game' 房间的所有客户端,包括发送者
io.in('game').emit('big-announcement', 'the game will start soon');
// 发送给同在 'myNamespace' 命名空间下的所有客户端,包括发送者
io.of('myNamespace').emit('bigger-announcement', 'the tournament will start soon');
// 发送给指定 socketid 的客户端(私密消息)
socket.to().emit('hey', 'I just met you');
// 包含回执的消息
socket.emit('question', 'do you think so?', function (answer) {});
// 不压缩,直接发送
socket.compress(false).emit('uncompressed', "that's rough");
// 如果客户端还不能接收消息,那么消息可能丢失
socket.volatile.emit('maybe', 'do you really need it?');
// 发送给当前 node 实例下的所有客户端(在使用多个 node 实例的情况下)
io.local.emit('hi', 'my lovely babies');
注意,在自定义事件时,不要与系统内部保留的事件名冲突:
服务端内置保留的事件名
error //错误事件
connect //连接
disconnect //断开
disconnecting //断开中
newListener //新监听器
removeListener //移除监听器
ping
pong
客户端内置保留的事件名
connect – 当成功连接时Emitted
disconnect – 当连接断开Emitted
error – 发送错误时Emitted
reconnect – 当开始重连时Emitted
reconnectAttempt – 当尝试重连时Emitted
部分内容未经测试,不保证参考资料的准确性,socket.io新版本可能有所变动,请自行鉴别使用。