1. 程式人生 > >使用Node.js+Socket.IO搭建WebSocket 實現多人群聊

使用Node.js+Socket.IO搭建WebSocket 實現多人群聊

今天我們做的就是無重新整理實時多人聊天,最終效果我們可以看下:

Node.js

Node.js採用C++語言編寫而成,它不是Javascript應用,而是一個Javascript的執行環境,據Node.js創始人Ryan Dahl回憶,他最初希望採用Ruby來寫Node.js,但是後來發現Ruby虛擬機器的效能不能滿足他的要求,後來他嘗試採用V8引擎,所以選擇了C++語言。

Node.js支援的系統包括*nux、Windows,這意味著程式設計師可以編寫系統級或者伺服器端的Javascript程式碼,交給Node.js來解釋執行。Node.js的Web開發框架Express,可以幫助程式設計師快速建立web站點,從2009年誕生至今,Node.js的成長的速度有目共睹,其發展前景獲得了技術社群的充分肯定。

Socket.IO

Socket.IO是一個開源的WebSocket庫,它通過Node.js實現WebSocket服務端,同時也提供客戶端JS庫。Socket.IO支援以事件為基礎的實時雙向通訊,它可以工作在任何平臺、瀏覽器或移動裝置。

Socket.IO支援4種協議:WebSocket、htmlfile、xhr-polling、jsonp-polling,它會自動根據瀏覽器選擇適合的通訊方式,從而讓開發者可以聚焦到功能的實現而不是平臺的相容性,同時Socket.IO具有不錯的穩定性和效能。

編碼實現:

1.安裝Node.js

根據自己的作業系統,去Node.js官網下載安裝即可。我的是nginx:

yum install nodejs
yum install npm 
如果成功安裝。在命令列輸入node -vnpm -v應該能看到相應的版本號。
node -v  
v0.10.26  
npm -v  
1.4.6

搭建WebSocket服務端

這個環節我們儘可能的考慮真實生產環境,把WebSocket後端服務搭建成一個線上可以用域名訪問的服務,如果你是在本地開發環境,可以換成本地ip地址,或者使用一個虛擬域名指向本地ip。

進入到工作目錄,/usr/local/nginx/html,新建一個名為package.json的檔案,內容

{
  "name": "realtime-server",
  "version": "0.0.1",
  "description": "my first realtime server",
  "dependencies": {}
}

接下來使用npm命令安裝expresssocket.io

1
2
npm install --save express
npm install --save socket.io

安裝成功後,應該可以看到工作目錄下生成了一個名為node_modules的資料夾,裡面分別是expresssocket.io,接下來可以開始編寫服務端的程式碼了,新建一個檔案:index.js

1
2
3
4
5
6
7
8
9
10
11
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應該可以看到正常的歡迎頁面。

如果你想要讓服務執行在線上伺服器,並且可以通過域名訪問的話,可以使用Nginx做代理,在nginx.conf中新增如下配置,然後將域名(比如:realtime.plhwin.com)解析到伺服器IP即可。

1
2
3
4
5
6
7
8
server
{
  listen       80;
  server_name  realtime.plhwin.com;
  location / {
    proxy_pass http://127.0.0.1:3000;
  }
}

完成以上步驟,http://realtime.plhwin.com:3000的後端服務就正常搭建了。

服務端程式碼實現

前面講到的index.js執行在服務端,之前的程式碼只是一個簡單的WebServer歡迎內容,讓我們把WebSocket服務端完整的實現程式碼加入進去,整個服務端就可以處理客戶端的請求了。完整的index.js程式碼如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
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;
			//線上人數+1
			onlineCount++;
		}

		//向所有客戶端廣播使用者加入
		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];
			//線上人數-1
			onlineCount--;

			//向所有客戶端廣播使用者退出
			io.emit('logout', {onlineUsers:onlineUsers, onlineCount:onlineCount, user:obj});
			console.log(obj.username+'退出了聊天室');
		}
	});

	//監聽使用者釋出聊天內容
	socket.on('message', function(obj){
		//向所有客戶端廣播發布的訊息
		io.emit('message', obj);
		console.log(obj.username+'說:'+obj.content);
	});

});

http.listen(3000, function(){
	console.log('listening on *:3000');
});

客戶端程式碼實現

進入客戶端工作目錄/workspace/wwwroot/plhwin/demo.plhwin.com/chat,新建一個index.html:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
<!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提供的客戶端JS檔案,在前面安裝服務端的步驟中,當npm安裝完socket.io並搭建起WebServer後,這個JS檔案就可以正常訪問了。

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

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

第4個client.js是完整的客戶端的業務邏輯實現程式碼,它的內容如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
(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後端伺服器
			this.socket = io.connect('ws://realtime.plhwin.com:3000');

			//告訴伺服器端有使用者登入
			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();
		}
	};
})();

至此所有的編碼開發工作全部完成了,在瀏覽器中開啟demo.plhwin.com/chat/就可以看到效果了。上面所有的客戶端和服務端的程式碼可以從Github上獲得,點這裡跳轉到Github專案主頁,或者在命令列將程式碼Clone到本地。

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

下載本地後有兩個資料夾clientserverclient資料夾是客戶端原始碼,可以放在Nginx/Apache的WebServer中,也可以放在Node.js的WebServer中。後面的server資料夾裡的程式碼是websocket服務端程式碼,放在Node.js環境中,使用npm安裝完

相關推薦

使用Node.js+Socket.IO搭建WebSocket 實現人群

今天我們做的就是無重新整理實時多人聊天,最終效果我們可以看下: Node.js Node.js採用C++語言編寫而成,它不是Javascript應用,而是一個Javascript的執行環境,據Node.js創始人Ryan Dahl回憶,他最初希望採用Ruby來寫Node

Node.js+Socket.io搭建簡單的websocket伺服器

    因為專案原因需要使用websocket這種全雙工的通訊方式,但是在後端伺服器還沒搭建好的情況下,就只能自己搭建一個測試伺服器,下面我將一步步的列舉單間過程; 開發工具:webstorm 1.服務端 第一步:新建一個專案資料夾,開啟webstorm,進入該專案資料

基於Node.js + socket.io實現WebSocket的聊天DEMO

原文摘自我的前端部落格,歡迎大家來訪問 簡介 最近看Node.js和HTML5,練手了一個簡易版的聊天DEMO,娛樂一下 為什麼需要socket.io? node.js提供了高效的服務端執行環境,但是由於瀏覽器端對HTML5的支援不一, 為了相容所有瀏覽器,提供卓越

Node.js(socket.io)+ html + js搭建簡單聊天工具

Node.js+ html + js搭建簡單聊天工具 環境準備 依賴模組 服務端 客戶端 執行 乾貨,直接擼程式碼 環境準備 Node.js 依賴模組 socket.io

node.js(socket.io)實現資料實時推送

1.setInterval每隔n秒去非同步拉取資料(缺點:更新不夠實時) 2. AJAX輪詢方式方式推送資料(缺點:服務端需要在死迴圈中反覆查詢資料庫) 3.websocket推送資料(缺點:僅支援html5標準的瀏覽器) socket.io的簡要介紹 所有客戶端都通過socket.io掛

H5+MUI+Node.js+Socket.io實現即時聊天以及傳送+圖片壓縮+圖片預覽儲存

<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width,i

cocos creator socket.ionode.js socket.io通訊

1)客戶端 if (window.io == null){ window.io = require("./3rd/socket-io.js"); } var socketio = { sio: null, connect: function (url) {

H5+MUI+Node.js+Socket.io群組即時聊天+傳送圖片+圖片壓縮

<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width,i

java Socket實現人群與私

關於Socket套接字的一些基本知識與認識可以參見上一篇或自行查閱。 ServerSocket和Socket實現群聊與私聊涉及到多執行緒程式設計,實現過程的重點是利用Socket通訊的原理,即不斷的在服務端和客戶端建立輸入輸出流來相互傳遞、交換資料等以達到通訊的目的。具體實

node+express+socket.io+mysql=通訊服務器搭建(一)

釋放 get future 連接mysql add .com 成功 query tp服務器 首發github/blog 歡迎大家評論給星 安裝 首先假定你已經安裝了 Node.js,接下來為你的應用創建一個目錄,然後安裝express-generator應用骨架 $ mkd

聊天室入門實戰(nodesocket.io實現)--第一章(實現登入群功能)

這幾天花時間寫了一個聊天室的demo,實現了登入,使用者名稱檢測,群聊,單聊,圖片傳送等功能,這個系列部落格會分為幾章講解,由淺入深,逐步優化,章節間關聯性較大,建議從第一章開始閱讀。由於水平有限,有說的不對的地方還請各位大佬們留言指正。有不清楚的地方也可以留言提問。該部

node.js利用captchapng模塊實現圖片驗證碼

parse math style ase 圖片驗證碼 all pre 驗證 parseint 安裝captchapng模塊 npm install captchapng nodejs中使用 var express = require(‘express‘); v

Node.js原生及Express方法實現註冊登錄原理

美化 set head ack function charset stat input col 由於本文只是實現其原理,所以沒有使用數據庫,只是在js裏面模擬數據庫,當然實際中還是需要用數據庫的。 1.node.js原生方法 ①html頁面,非常簡單,沒有一絲美化~我們叫它

node.js後臺快速搭建在阿裏雲(二)(pm2和nginx篇)

logs down key version c-c 6.2 文檔 實例 gin 前期準備 阿裏雲服務器 node.js pm2 express nginx linux(推薦教程:鳥哥的私房菜) 簡介 嗯……我只是

使用Node.js+Hexo+Github搭建個人博客(續)

bsp 同步 歷程 str 基礎上 配置 搭建 創建 pan 一、寫在前面 在我的上一篇博客《使用Nodejs+Hexo+Github搭建個人博客》中,已經介紹了如何使用 Hexo 在 Github Pages 上搭建一個簡單的個人博客。該篇博文將在上篇博文的基礎上分別從

Vue+Websocket實現人在線王者飛機(一)

Vue requestAnimationFra 飛機大戰 WebSocket 看了Vue官方教程(貌似和自己寫的框架差別不大,聽前前端同事一直吹Vue,於是學習了一下,和自己寫的框架好像也沒強哪裏去嘛,就是要傲嬌哈哈),等有空也整理自己的框架,開源好了),想找個項目練練手(沒找到好的),就寫個

nodesocket.io搭配小例子-轉載

pst border ava bsp lob vps min 信息 click //服務端代碼 io = require(‘socket.io‘).listen(app), fs = require(‘fs‘), cookie=require(‘cookie‘);

node.js + gulp 環境搭建

info 使用命令 http src inf image 圖片 ima 分享 10.25工作記錄 node.js 安裝下載 : https://nodejs.org/en/ 安裝完node.js後,使用命令行安裝gulp.js 命令:npm i

node.js&pm2搭建node生產環境

本文以 centos 6.5 x64 為例 node.js 下載地址 https://nodejs.org/en/download/stable/ 建議採用穩定編譯過的版本,source code稍麻煩,編譯過的直接可用,安裝超級簡單,紅色的是centos X64可用地址。

node.js+mongodb資料庫 搭建後臺

首先下載資料庫 連結: https://pan.baidu.com/s/1lw_qal0vcvGm3wiJC-F9xQ 提取碼: ctj5 這裡我提供一下我百度網盤的資料庫安裝包 建立一個資料夾mymongodb,這裡為mongodb資料庫的安裝位置。 在此資料夾下建立data資