推送服務之socket.io


一、作者自述

  從事軟件開發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已經和詳細了。有需求的同學可以自行查看文檔。

最后

  第一次寫博客,很多地方都寫的比較簡陋,望請諒解!

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM