在Html5中存在着這種一個新特性。引入了websocket,關於websocket的內部實現原理可以看這篇文章。這篇文章講述了websocket無到有,依據協議,分析數據幀的頭,進行構建websocket。儘管代碼短。但可以很是好地體現websocket的原理。
http://blog.csdn.net/newpidian/article/details/50850670javascript
,這個特性提供了瀏覽器端和server端的基於TCP鏈接的雙向通道。css
但是並不是所有的瀏覽器都支持websocket特性。故爲了磨平瀏覽器間的差別,爲開發人員提供統一的接口,引入了socket.io模塊。在不支持websoket的瀏覽器中,socket.io可以降級爲其它的通訊方式,比方有AJAX long polling 。JSONP Polling等。html
模塊安裝
新建一個package.json文件,在文件裏寫入例如如下內容:java
{
"name": "socketiochatroom",
"version": "0.0.1",
"dependencies": { "socket.io": "*", "express":"*" } }
npm install
執行完這句,node將會從npm處下載socket.io和express模塊。node
在文件夾中增長index.js文件,並在文件裏寫入例如如下內容:web
/** * Created by bamboo on 2016/3/31. */
var app = require('express')();
var http = require('http').Server(app);
var io = require('socket.io')(http);
app.get('/', function (req, res) {
"use strict";
res.end("<h1>socket server</h1>")
});
/*在線人員*/
var onLineUsers = {};
/* 在線人數*/
var onLineCounts = 0;
/*io監聽到存在連接。此時回調一個socket進行socket監聽*/
io.on('connection', function (socket) {
console.log('a user connected');
/*監聽新用戶增長*/
socket.on('login', function (user) {
"use strict";
//暫存socket.name 爲user.userId;在用戶退出時候將會用到
socket.name = user.userId;
/*不存在則增長 */
if (!onLineUsers.hasOwnProperty(user.userId)) {
//不存在則增長
onLineUsers[user.userId] = user.userName;
onLineCounts++;
}
/*一個用戶新增長,向所有client監聽login的socket的實例發送響應,響應內容爲一個對象*/
io.emit('login', {onLineUsers: onLineUsers, onLineCounts: onLineCounts, user: user});
console.log(user.userName, "增長了聊天室");//在server控制檯中打印麼麼麼用戶增長到了聊天室
});
/*監聽用戶退出聊天室*/
socket.on('disconnect', function () {
"use strict";
if (onLineUsers.hasOwnProperty(socket.name)) {
var user = {userId: socket.name, userName: onLineUsers[socket.name]};
delete onLineUsers[socket.name];
onLineCounts--;
/*向所有client廣播該用戶退出羣聊*/
io.emit('logout', {onLineUsers: onLineUsers, onLineCounts: onLineCounts, user: user});
console.log(user.userName, "退出羣聊");
}
})
/*監聽到用戶發送了消息。就使用io廣播信息。信息被所有client接收並顯示。注意。假設client本身發送的也會接收到這個消息,故在client應當存在這的推斷。是否收到的消息是本身發送的。故在emit時,應該將用戶的id和信息封裝成一個對象進行廣播*/
socket.on('message', function (obj) {
"use strict";
/*監聽到實用戶發消息,將該消息廣播給所有client*/
io.emit('message', obj);
console.log(obj.userName, "說了:", obj.content);
});
});
/*監聽3000*/
http.listen(3000, function () {
"use strict";
console.log('listening 3000');
});
node index.js
輸出express
listening 3000
此時在瀏覽器中打開localhost:3000會獲得這種結果:
npm
緣由是在代碼中僅僅對路由進行了例如如下設置json
app.get('/', function (req, res) {
"use strict";
res.end("<h1>socket server</h1>")
});
server端主要是提供socketio服務,並無設置路由。瀏覽器
在client創建例如如下的文件夾和文件。當中json3.min.js可以從網上下載到。
client
- - - client.js
- - - index.html
- - - json3.min.js
- - - style.css
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="format-detection" content="telephone=no"/>
<meta name="format-detection" content="email=no"/>
<title>1301羣聊</title>
<link rel="stylesheet" type="text/css" href="./style.css"/>
<script src="http://realtime.plhwin.com:3000/socket.io/socket.io.js"></script>
<script src="./json3.min.js"></script>
</head>
<body>
<div id="loginbox">
<div style="width: 260px;margin: 200px auto;">
輸入你在羣聊中的暱稱
<br/>
<br/>
<input type="text" style="width:180px;" placeholder="請輸入username" 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;">1301羣聊</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="onLineCounts" 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="輸入聊天內容 " 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>
/** * Created by bamboo on 2016/3/31. */
/*即時執行函數*/
(function () {
"use strict";
var d = document,
w = window,
dd = d.documentElement,
db = d.body,
dc = d.compatMode === "CSS1Compat",
dx = dc ? dd : db,
ec = encodeURIComponent,
p = parseInt;
w.CHAT = {
msgObj: d.getElementById("message"),
screenHeight: w.innerHeight ? w.innerHeight : dx.innerHeight, userName: null, userId: null, socket: null, /*滾動欄始終在最底部*/ scrollToBottom: function () { w.scrollTo(0, this.msgObj.clientHeight); }, /*此處僅爲簡單的刷新頁面,固然可以作複雜點*/ logout: function () { // this.socket.disconnect(); w.top.location.reload(); }, submit: function () { var content = d.getElementById('content').value; if (content != '') { var obj = { userId: this.userId, userName: this.userName, content: content }; //如在server端代碼所說,此對象便可想要發送的信息和發送人組合成爲對象一塊兒發送。 this.socket.emit('message', obj); d.getElementById('content').value = ''; } return false; }, /**client依據時間和隨機數生成ID,聊天username稱可以反覆*/ genUid: function () { return new Date().getTime() + "" + Math.floor(Math.random() * 889 + 100); }, /*更新系統信息 主要是在client顯示當前在線人數。在線人列表等,當有新用戶增長或者舊用戶退出羣聊的時候作出頁面提示。*/ updateSysMsg: function (o, action) { var onLineUsers = o.onLineUsers; var onLineCounts = o.onLineCounts; var user = o.user; //更新在線人數 var userHtml = ''; var separator = ''; for (var key in onLineUsers) { if (onLineUsers.hasOwnProperty(key)) { userHtml += separator + onLineUsers[key]; separator = '、'; } } //插入在線人數和在線列表 d.getElementById('onLineCounts').innerHTML = '當前共同擁有' + onLineCounts + "在線列表: " + 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(); }, /*用戶提交username後,將loginbox設置爲不顯示,將chatbox設置爲顯示*/ 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);//調用init方法 } return false; }, //用戶初始化 init: function (userName) { //隨機數生成uid this.userId = this.genUid(); this.userName = userName; d.getElementById('showUserName').innerHTML = this.userName;//[newpidian]|[退出] this.scrollToBottom(); //鏈接socketIOserver,newpidian的IP地址 this.socket = io.connect('192.168.3.155:3000'); //向server發送某用戶已經登陸了 this.socket.emit('login', {userId: this.userId, userName: this.userName}); //監聽來自server的login,即在clientsocket.emit('login ')發送後,client就會收到來自server的 // io.emit('login', {onLineUsers: onLineUsers, onLineCounts: onLineCounts, user: user}); /*監聽到實用戶login了,更新信息*/ this.socket.on('login', function (o) { //更新系統信息 CHAT.updateSysMsg(o, 'login'); }); /*監聽到實用戶logout了,更新信息*/ this.socket.on('logout', function (o) { CHAT.updateSysMsg(o, 'logout'); }); //var obj = { // userId: this.userId, // userName: this.userName, // content: content //}; /*監聽到實用戶發送消息了*/ this.socket.on("message", function (obj) { //推斷消息是否是本身發送的 var isMe = (obj.userId === CHAT.userId); 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(); }); } } /*控制鍵鍵碼值(keyCode) 按鍵 鍵碼 按鍵 鍵碼 按鍵 鍵碼 按鍵 鍵碼 BackSpace 8 Esc 27 Right Arrow 39 -_ 189 Tab 9 Spacebar 32 Dw Arrow 40 .> 190 Clear 12 Page Up 33 Insert 45 /? 191 Enter 13 Page Down 34 Delete 46 `~ 192 Shift 16 End 35 Num Lock 144 [{ 219 Control 17 Home 36 ;: 186 \| 220 Alt 18 Left Arrow 37 =+ 187 ]} 221 Cape Lock 20 Up Arrow 38 ,< 188 '" 222 * */ //經過「回車鍵」提交username d.getElementById('userName').onkeydown = function (e) { console.log(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(); } }; })();
祕密
server端已經執行。現將client也執行起來獲得下圖:
增長了new和pidian兩個用戶。併發送信息和進行退出,獲得如下的結果: