HTML5新特性之WebSocket

來源:互聯網
上載者:User

標籤:named   社區   name   this   minimum   更新   inpu   隨機   names   

一、WebSocket簡單介紹:

     談到Web即時推送,就不得不說WebSocket。在WebSocket出現之前,非常多網站為了實現即時推送技術。通常採用的方案

是輪詢(Polling)和Comet技術,Comet又可細分為兩種實現方式,一種是長輪詢機制。一種稱為流技術。這兩種方式實際上是對

輪詢技術的改進。這些方案帶來非常明顯的缺點,須要由瀏覽器對server發出HTTP request。大量消耗server頻寬和資源。面對

這樣的狀況。HTML5定義了WebSocket協議,能更好的節省server資源和頻寬並實現真正意義上的即時推送。

     WebSocket協議本質上是一個基於TCP的協議。它由通訊協定和編程API組成,WebSocket可以在瀏覽器和server之間建立

雙向串連,以基於事件的方式,賦予瀏覽器即時通訊能力。既然是雙向通訊。就意味著server端和client能夠同一時候發送並響應請

求。而不再像HTTP的請求和響應。

     為了建立一個WebSocket串連。client瀏覽器首先要向server發起一個HTTP請求,這個請求和通常的HTTP請求不同。包括

了一些附加頭資訊。當中附加頭資訊”Upgrade: WebSocket”表明這是一個申請協議升級的HTTP請求,server端解析這些附加的

頭資訊然後產生應答資訊返回給client。client和server端的WebSocket串連就建立起來了。兩方就能夠通過這個串連通道自由

的傳遞資訊。而且這個串連會持續存在直到client或者server端的某一方主動的關閉串連。

     一個典型WebSocketclient要求標頭:


     注意:WebSocket是HTML5中新增的一種通訊協定,這意味著一部分老版本號碼瀏覽器(主要是IE10下面版本號碼)並不具備這個功能。 

通過百度統計的公開資料顯示,IE8眼下仍以33%的市場份額佔領榜首,好在chrome瀏覽器市場份額逐年上升,如今以超過26%的

市場份額位居第二,同一時候微軟前不久宣布停止對IE6的支援人員並提示使用者更新到新版本號碼瀏覽器。這個以前讓無數前端project師為之頭

疼的瀏覽器有望退出曆史舞台,再加上差點兒全部的智能手機瀏覽器都支援HTML5,所以使得WebSocket的實戰意義大增。可是不管

怎樣,我們實際的項目中,仍然要考慮低版本號碼瀏覽器的相容方案:在支援WebSocket的瀏覽器中採用新技術,而在不支援WebSocke

t的瀏覽器裡啟用Comet來接收發送訊息。

     瀏覽器支援列表:



二、WebSocket實戰:

     本文將以多人線上聊天應用作為執行個體情境。我們先來確定這個聊天應用的基本需求。

需求分析:

1、相容不支援WebSocket的低版本號碼瀏覽器。

2、同意client有同樣的username。

3、進入聊天室後能夠看到當前線上的使用者和線上人數。

4、使用者上線或退出,全部線上的client應該即時更新。

5、使用者發送訊息,全部client即時收取。


     在實際的開發過程中。為了使用WebSocket介面構建Web應用。我們首先須要構建一個實現了 WebSocket規範的服務端。

服務端的實現不受平台和開發語言的限制,僅僅須要遵從WebSocket規範就可以。眼下已經出現了一些比較成熟的 WebSocket

服務端實現,比方本文使用的Node.js+Socket.IO。

為什麼選用這個方法呢?以下將先進行介紹。


Node.js:

     Node.js採用C++語言編寫而成。它不是Javascript應用,而是一個Javascript的執行環境。據Node.js創始人 Ryan Dahl回顧。

他最初希望採用Ruby來寫Node.js,可是後來發現Ruby虛擬機器的效能不能滿足他的要求,後來他嘗試採用V8引擎。所以選擇

了 C++語言。

     Node.js支援的系統包含*nux、Windows,這意味著程式猿能夠編寫系統級或者server端的Javascript代碼。交給 Node.js來

解釋運行。Node.js的Web開發架構Express。能夠協助程式猿高速建立web網站,從2009年誕生至今,Node.js的 成長的速度

有目共睹,其發展前景獲得了技術社區的充分肯定。


Socket.IO:
     Socket.IO是一個開源的WebSocket庫,它通過Node.js實現WebSocket服務端,同一時候也提供clientJS庫。

Socket.IO支援以

事件為基礎的即時雙向通訊。它能夠工作在不論什麼平台、瀏覽器或行動裝置。

     Socket.IO支援4種協議:WebSocket、htmlfile、xhr-polling、jsonp-polling。它會自己主動依據瀏覽 器選擇適合的通訊方式,

從而讓開發人員能夠聚焦到功能的實現而不是平台的相容性。同一時候Socket.IO具有不錯的穩定性和效能。


終於效果:


開發步驟

(1)、安裝Node.js

     依據作業系統,去Node.js官網下載安裝。假設安裝成功。在命令列輸入node -v和npm -v應該能看到對應的版本。

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" >

(2)、搭建WebSocket服務端

     這個環節我們儘可能的考慮真實生產環境。把WebSocket後端服務搭建成一個線上能夠用網域名稱訪問的服務,假設你是在本地開發環境,

能夠換成本地ip地址,或者使用一個虛擬網域名稱指向本地ip。

     先進入到你的工作資料夾。比方 /workspace/wwwroot/plhwin/realtime.plhwin.com,建立一個名為 package.json的檔案,內容例如以下:

{  "name": "realtime-server",  "version": "0.0.1",  "description": "my first realtime server",  "dependencies": {}}
     接下來使用npm命令安裝express和socket.io
npm install --save expressnpm install --save socket.io
     成功安裝後。應該能夠看到工作資料夾下產生了一個名為node_modules的檔案夾,裡面各自是express和socket.io,接下來能夠開始編寫

服務端的代碼了。建立一個檔案:index.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');});
      命令列執行node index.js。假設一切順利,你應該會看到返回的listening on *:3000字樣,這說明服務已經成功搭建了。

此時瀏覽器中開啟

http://localhost:3000應該能夠看到正常的歡迎頁面。

假設你想要讓服務執行線上上server。而且能夠通過網域名稱訪問的話,能夠使用Nginx做代理。在nginx.conf中加入例如以下配置,然後將網域名稱

(比方:realtime.plhwin.com)解析到serverIP就可以。

 server  {    listen       80;    server_name  realtime.plhwin.com;    location / {      proxy_pass http://127.0.0.1:3000;    }  }
     完畢以上步驟,http://realtime.plhwin.com:3000的後端服務就正常搭建了。

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" >

(3)、服務端代碼實現

     前面講到的index.js執行在服務端,之前的代碼僅僅是一個簡單的WebServer歡迎內容,讓我們把WebSocket服務端完整的實現代碼增加進去,

整個服務端就能夠處理client的請求了。完整的index.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>');});//線上使用者var onlineUsers = {};//當前線上人數var onlineCount = 0;io.on('connection', function(socket){console.log('a user connected');//監聽新使用者增加socket.on('login', function(obj){//將新增加使用者的唯一標識當作socket的名稱。後面退出的時候會用到socket.name = obj.userid;//檢查線上列表,假設不在裡面就增加if(!onlineUsers.hasOwnProperty(obj.userid)) {onlineUsers[obj.userid] = obj.username;//線上人數+1onlineCount++;}//向全部client廣播使用者增加io.emit('login', {onlineUsers:onlineUsers, onlineCount:onlineCount, user:obj});console.log(obj.username+'增加了聊天室');});//監聽使用者退出socket.on('disconnect', function(){//將退出的使用者從線上列表中刪除if(onlineUsers.hasOwnProperty(socket.name)) {//退出使用者的資訊var obj = {userid:socket.name, username:onlineUsers[socket.name]};//刪除delete onlineUsers[socket.name];//線上人數-1onlineCount--;//向全部client廣播使用者退出io.emit('logout', {onlineUsers:onlineUsers, onlineCount:onlineCount, user:obj});console.log(obj.username+'退出了聊天室');}});//監聽使用者公布聊天內容socket.on('message', function(obj){//向全部client廣播公布的訊息io.emit('message', obj);console.log(obj.username+'說:'+obj.content);});  });http.listen(3000, function(){console.log('listening on *:3000');});

四、client代碼實現

     進入client工作資料夾/workspace/wwwroot/plhwin/demo.plhwin.com/chat。建立一個index.html:

<!DOCTYPE html><html>    <head>        <meta charset="utf-8">        <meta name="format-detection" content="telephone=no"/>        <meta name="format-detection" content="email=no"/>        <meta content="width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, user-scalable=0" name="viewport">        <title>多人聊天室</title>        <link rel="stylesheet" type="text/css" href="./style.css" />        <!--[if lt IE 8]><script src="./json3.min.js"></script><![endif]-->        <script src="http://realtime.plhwin.com:3000/socket.io/socket.io.js"></script>    </head>    <body>        <div id="loginbox">            <div style="width:260px;margin:200px auto;">                請先輸入你在聊天室的暱稱                <br/>                <br/>                <input type="text" style="width:180px;" placeholder="請輸入使用者名稱" id="username" name="username" /><input type="button" style="width:50px;" value="提交" onclick="CHAT.usernameSubmit();"/>            </div>        </div>        <div id="chatbox" style="display:none;">            <div style="background:#3d3d3d;height: 28px; width: 100%;font-size:12px;">                <div style="line-height: 28px;color:#fff;">                    <span style="text-align:left;margin-left:10px;">Websocket多人聊天室</span>                    <span style="float:right; margin-right:10px;"><span id="showusername"></span> | <a href="javascript:;" onclick="CHAT.logout()" style="color:#fff;">退出</a></span>                </div>            </div>            <div id="doc">                <div id="chat">                    <div id="message" class="message"><div id="onlinecount" style="background:#EFEFF4; font-size:12px; margin-top:10px; margin-left:10px; color:#666;"></div>                    </div>                    <div class="input-box">                        <div class="input"><input type="text" maxlength="140" placeholder="請輸入聊天內容,按Ctrl提交" id="content" name="content">                        </div>                        <div class="action">                            <button type="button" id="mjr_send" onclick="CHAT.submit();">提交</button>                        </div>                    </div>                </div>            </div>        </div>        <script type="text/javascript" src="./client.js"></script>    </body></html>

上面的html內容本身沒有什麼好說的,我們主要看看裡面的4個檔案請求:

1、realtime.plhwin.com:3000/socket.io/socket.io.js

2、style.css

3、json3.min.js

4、client.js

第1個JS是Socket.IO提供的clientJS檔案,在前面安裝服務端的步驟中,當npm安裝完socket.io並搭建起WebServer後,這個JS檔案就能夠正常訪問了。

第2個style.css檔案沒什麼好說的。就是樣式檔案而已。

第3個JS僅僅在IE8下面版本號碼的IE瀏覽器中載入,目的是讓這些低版本號碼的IE瀏覽器也能處理json。這是一個開源的JS,詳見:http://bestiejs.github.io/json3/

第4個client.js是完整的用戶端的商務邏輯實現代碼,它的內容例如以下:

(function () {var d = document,w = window,p = parseInt,dd = d.documentElement,db = d.body,dc = d.compatMode == 'CSS1Compat',dx = dc ?

dd: db,ec = encodeURIComponent;w.CHAT = {msgObj:d.getElementById("message"),screenheight:w.innerHeight ? w.innerHeight : dx.clientHeight,username:null,userid:null,socket:null,//讓瀏覽器滾動欄保持在最低部scrollToBottom:function(){w.scrollTo(0, this.msgObj.clientHeight);},//退出,本例僅僅是一個簡單的重新整理logout:function(){//this.socket.disconnect();location.reload();},//提交聊天訊息內容submit:function(){var content = d.getElementById("content").value;if(content != ''){var obj = {userid: this.userid,username: this.username,content: content};this.socket.emit('message', obj);d.getElementById("content").value = '';}return false;},genUid:function(){return new Date().getTime()+""+Math.floor(Math.random()*899+100);},//更新系統訊息,本例中在使用者增加、退出的時候調用updateSysMsg:function(o, action){//當前線上使用者列表var onlineUsers = o.onlineUsers;//當前線上人數var onlineCount = o.onlineCount;//新增加使用者的資訊var user = o.user;//更新線上人數var userhtml = '';var separator = '';for(key in onlineUsers) { if(onlineUsers.hasOwnProperty(key)){userhtml += separator+onlineUsers[key];separator = '、';} }d.getElementById("onlinecount").innerHTML = '當前共同擁有 '+onlineCount+' 人線上,線上列表:'+userhtml;//增加系統訊息var html = '';html += '<div class="msg-system">';html += user.username;html += (action == 'login') ? ' 增加了聊天室' : ' 退出了聊天室';html += '</div>';var section = d.createElement('section');section.className = 'system J-mjrlinkWrap J-cutMsg';section.innerHTML = html;this.msgObj.appendChild(section);this.scrollToBottom();},//第一個介面使用者提交使用者名稱usernameSubmit:function(){var username = d.getElementById("username").value;if(username != ""){d.getElementById("username").value = '';d.getElementById("loginbox").style.display = 'none';d.getElementById("chatbox").style.display = 'block';this.init(username);}return false;},init:function(username){/*用戶端依據時間和隨機數產生uid,這樣使得聊天室使用者名稱稱能夠反覆。實際項目中,假設是須要使用者登入,那麼直接採用使用者的uid來做標識就能夠*/this.userid = this.genUid();this.username = username;d.getElementById("showusername").innerHTML = this.username;this.msgObj.style.minHeight = (this.screenheight - db.clientHeight + this.msgObj.clientHeight) + "px";this.scrollToBottom();//串連websocket後端serverthis.socket = io.connect('ws://realtime.plhwin.com:3000');//告訴server端實使用者登入this.socket.emit('login', {userid:this.userid, username:this.username});//監聽新使用者登入this.socket.on('login', function(o){CHAT.updateSysMsg(o, 'login');});//監聽使用者退出this.socket.on('logout', function(o){CHAT.updateSysMsg(o, 'logout');});//監聽訊息發送this.socket.on('message', function(obj){var isme = (obj.userid == CHAT.userid) ? true : false;var contentDiv = '<div>'+obj.content+'</div>';var usernameDiv = '<span>'+obj.username+'</span>';var section = d.createElement('section');if(isme){section.className = 'user';section.innerHTML = contentDiv + usernameDiv;} else {section.className = 'service';section.innerHTML = usernameDiv + contentDiv;}CHAT.msgObj.appendChild(section);CHAT.scrollToBottom();});}};//通過“斷行符號”提交使用者名稱d.getElementById("username").onkeydown = function(e) {e = e || event;if (e.keyCode === 13) {CHAT.usernameSubmit();}};//通過“斷行符號”提交資訊d.getElementById("content").onkeydown = function(e) {e = e || event;if (e.keyCode === 13) {CHAT.submit();}};})();

至此所有的編碼開發工作所有完畢了。在瀏覽器中開啟http://demo.plhwin.com/chat/就能夠看到效果了。

上面全部的client和服務端的代碼能夠從Github上獲得,地址:https://github.com/plhwin/nodejs-socketio-chat

git clone https://github.com/plhwin/nodejs-socketio-chat.git 

    下載本地後有兩個目錄 client 和 server,client目錄是用戶端原始碼,能夠放在Nginx/Apache的WebServer中,

也能夠放在Node.js的WebServer中。後面的server目錄裡的代碼是websocket服務端代碼。放在Node.js環境中

,使用npm安裝完 express 和 socket.io 後,node index.js 啟動後端服務就能夠了。

     本例僅僅是一個簡單的Demo,留下2個有關項目擴充的思考:

     1、如果是一個線上客服系統,裡面有很多的公司使用你的服務,每一個公司自己的使用者能夠通過一個專屬URL地址

進入該公司的聊天室,聊天是一對一的,每一個公司能夠建立多個客服人員,每一個客服人員能夠同一時候和client的多個使用者聊天。

     2、又如果是一個線上WebIM系統,實作類別似。qq的功能,client能夠看到好友線上狀態,線上列表。加入好友,

移除朋友。建立群組等。訊息的發送除了支援主要的文字外。還能支援表情、圖片和檔案。

來自:http://www.plhwin.com/2014/05/28/nodejs-socketio/

HTML5新特性之WebSocket

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.