一、作者自述
从事软件开发3年了,出于各种原因(其实是因为我懒,啊哈哈~),第一次决定动手写点什么。第一呢,给自己一个总结的机会,梳理下自己的知识库。第二呢,同第一点。。。
自从大学毕业后,一直处于一种“极度”的繁忙之中。从刚开始入行时各种学习的“饥渴”状态,到后来工作需要的“填鸭”状态,一直在学,一直在用,边用边学。刚开始接触的知识面比较窄,但随着工作的变换,能力的提升,接触的东西越来越多了。慢慢的,自己越来越感觉知识杂乱,缺乏梳理。因此,决定开通博客,时不时的记录下自己新学的知识,整理下已经学过的知识,偶尔来灵感了,也可以总结一下。
二、推送服务之socket.io
目前来说,接触到的推送服务也有几个了。比如signalr,socket.io,super websocket。除此之外还有其他第三方推送服务。对于一个前后端都得啃的苦逼猿来说,总体感觉原理都是差不多的。最大的不同可能就是其实现方式的不同了。在此不多做追述,有兴趣的童鞋可以自行百度。
今天来重点说下socket.io。接触socket.io是因为公司要开发一款棋牌游戏,决定使用socket.io作为推送服务。和前面说的另外两个推送不一样,socket.io是跑在node环境下的服务。不得不说,JS编程确实快捷简单。没用过node的童鞋,可以找度娘。废话不多说,直接上代码。
socket.io服务端代码:
1 var app = require(‘http‘).createServer(handler) 2 var io = require(‘socket.io‘)(app); 3 var fs = require(‘fs‘); 4 5 app.listen(80); 6 7 io.on(‘connection‘, function (socket) { 8 socket.emit(‘news‘, { hello: ‘world‘ }); 9 socket.on(‘my other event‘, function (data) { 10 console.log(data); 11 }); 12 });
socket.io客户端代码:
1 <script src="/socket.io/socket.io.js"></script> 2 <script> 3 var socket = io(‘http://localhost‘); 4 socket.on(‘news‘, function (data) { 5 console.log(data); 6 socket.emit(‘my other event‘, { my: ‘data‘ }); 7 }); 8 </script>
简单解释下
<script src="/socket.io/socket.io.js"></script>
该行代码用来指示socket.io服务所在地址。若服务端与客户端不在同一项目内,则需要添加上服务所在具体域名或者IP和端口。
至此,我们的推送服务带客户端简单交互已经完成了。当然,相当的简陋。此例就是官方给出的demo,非常的简单,直白。但是我们在实际的运用当中,需求肯定不会如此的简单。
先说下socket.io的部分API,1.0版本之前的API和1.0之后版本的API已经有所不同了(其实我感觉这里描述为事件更贴切)。这里简单列下1.0版本之后的API。
socket.io 提供了默认事件(如:connect, message, disconnect)。另外,socket.io允许发送并接收自定义事件。
自定义事件:
1 socket.on(‘send message‘, function(data) { 2 console.log(‘send message:::::::::‘, data); 3 });
事件的定义基本不变。所有的事件基本都是这个格式。
执行事件:
socket.emit("send message", {msg: ‘test send messsage‘});
这是个最基本的事件执行代码。其作用是返回一段提示信息给自己。其他人无法接收到。如果我们要给别人发送消息怎么办呢??
io.sockets.connected[socket.id].emit(‘send message‘, {msg: ‘test specific message‘});
此行代码的作用就是给特定socket发送消息。只需要知道目标的socketId即可。因此,服务端最好要实现处理用户和socke关系的业务。
socket.broadcast.to(socket.id).emit(‘send message‘, {msg: ‘test specific message by room‘});
这行代码的效果和上面一样是一样的。用户在建立socket链接后,默认都会加入一个room,该room的ID就是socket的ID。相当于一个特定的房间内只有一个用户。我们想该房间通知消息,该用户就可以接收到。不同的是上面的代码可以给自己发送消息,而本行代码不行,只能给别人发送消息。
广播消息:
1 //全局广播消息(不包含自己) 2 socket.broadcast.emit(‘broadcast message‘, {msg: ‘test broadcast message‘}); 3 //房间内广播消息(不包括自己) 4 socket.broadcast.to(‘cg room‘).emit(‘broadcast message to room‘, {msg: ‘test broadcast message to room‘}); 5 //全局广播消息(包括自己) 6 io.sockets.emit(‘broadcast message all‘, {msg: ‘test broadcast message to all‘}); 7 //房间内广播消息(包括自己) 8 io.sockets.to(‘cg room‘).emit(‘broadcast message all in room‘, {msg: ‘test broadcast message to all in room‘});
这几行代码的作用是向某一范围内,所有已链接的socket发送消息。网上看到想房间内发送消息的时候,有的用in,有的用to,区别是in自己可以接收到,to自己接收不到。但我测试的结果是这俩其实是一样的。想房间内通知消息,是否需要屏蔽自己,也不是通过in和to来区分的。这可能是老版本和新版本的区别吧。
推送,其实就是客户端A向服务器主动发送一条消息,服务器收到并根据要求进行转发,此时B客户端作为接收方,被动的接收服务器转发过来的数据。当然,中间涉及到用户状态的变更和维护。这里不做描述。而某些情况下,我们需要知道服务器或者客户端是否收到了发送过去的数据,我们可以发送带有确认机制的消息:
//Sending and getting data (acknowledgements) socket.emit(‘ack message‘, {msg: ‘test ack message‘}, function (data){ //回掉返回的确认消息,可以为任意JS支持的类型 console.log(data); });
其对应的事件定义方式需要改动一下:
socket.on(‘ack message‘, function(data, fn) { console.log(‘ack message:::::::::‘, data); fn(true); });
此外,socket.io还提供一种消息发送机制volatile messages。意思大概是说,当服务器发送数据时,客户端因为各种原因不能正常接收,比如网络问题、或者正处于长连接的建立连接阶段。此时会让我们的应用变得 suffer(意会一下),那就需要考虑发送 volatile 数据。即使客户端没连线,一样可以这样发送,服务器会自动丢弃发送失败的数据。这里提供一个官方demo:
1 var io = require(‘socket.io‘)(80); 2 3 io.on(‘connection‘, function (socket) { 4 var tweets = setInterval(function () { 5 getBieberTweet(function (tweet) { 6 socket.volatile.emit(‘bieber tweet‘, tweet); 7 }); 8 }, 100); 9 10 socket.on(‘disconnect‘, function () { 11 clearInterval(tweets); 12 }); 13 });
房间和命名空间
这里不再具体赘述,官网给的demo已经和详细了。有需求的同学可以自行查看文档。
最后
第一次写博客,很多地方都写的比较简陋,望请谅解!