您好,登錄后才能下訂單哦!
本文,我們通過(guò)Egret和Node.js實(shí)現(xiàn)一個(gè)在線聊天室的demo。主要包括:聊天,改用戶名,查看其他用戶在線狀態(tài)的功能。大致流程為,用戶訪問(wèn)網(wǎng)頁(yè),即進(jìn)入聊天狀態(tài),成為新游客,通過(guò)底部的輸入框,可以輸入自己想說(shuō)的話,點(diǎn)擊發(fā)布,信息呈現(xiàn)給所有在聊天的人的頁(yè)面。用戶可以實(shí)時(shí)修改自己的昵稱,用戶離線上線都會(huì)實(shí)時(shí)廣播給其他用戶。
體驗(yàn)鏈接 http://7hds.com:8888/
下圖為最終制作完成的聊天面板
WebSocket服務(wù)器可以用其他語(yǔ)言編寫,本文采用的方法建立在Node.js上 。
在Node.js中我們使用ws第三方模塊來(lái)實(shí)現(xiàn)服務(wù)器業(yè)務(wù)邏輯的快速搭建,還需使用uuid模塊生成隨機(jī)id,你需要使用npm包管理器來(lái)安裝ws、uuid模塊。使用以下命令:
npm install ws -g
npm install uuid -g
安裝完成之后,使用終端工具進(jìn)入服務(wù)器目錄,開(kāi)始編寫代碼:
//引入ws模塊
var WebSocket = require('ws');
//創(chuàng)建websocket服務(wù),端口port為:****
var WebSocketServer = WebSocket.Server,
wss = new WebSocketServer({port: 8180});
//引入uuid模塊
var uuid = require('node-uuid');
//定義一個(gè)空數(shù)組,存放客戶端的信息
var clients = [];
//定義發(fā)送消息方法wsSend
//參數(shù)為 type:類型
//client_uuid:隨機(jī)生成的客戶端id
//nickname:昵稱
//message:消息
//clientcount:客戶端個(gè)數(shù)
function wsSend(type, client_uuid, nickname, message,clientcount) {
//遍歷客戶端
for(var i=0; i<clients.length; i++) {
//聲明客戶端
var clientSocket = clients[i].ws;
if(clientSocket.readyState === WebSocket.OPEN) {
//客戶端發(fā)送處理過(guò)的信息
clientSocket.send(JSON.stringify({
"type": type,
"id": client_uuid,
"nickname": nickname,
"message": message,
"clientcount":clientcount,
}));
}
}
}
//聲明客戶端index默認(rèn)為1
var clientIndex = 1;
//服務(wù)端連接
wss.on('connection', function(ws) {
//客戶端client_uuid隨機(jī)生成
var client_uuid = uuid.v4();
//昵稱為游客+客戶端index
var nickname = "游客"+clientIndex;
//client++
clientIndex+=1;
//將新連接的客戶端push到clients數(shù)組中
clients.push({"id": client_uuid, "ws": ws, "nickname": nickname});
//控制臺(tái)打印連接的client_uuid
console.log('client [%s] connected', client_uuid);
//聲明連接信息為 昵稱+來(lái)了
// var connect_message = nickname + " 來(lái)了";
var connect_message = " 來(lái)了";
//服務(wù)器廣播信息 ***來(lái)了
wsSend("notification", client_uuid, nickname, connect_message,clients.length);
//當(dāng)用戶發(fā)送消息時(shí)
ws.on('message', function(message) {
// 用戶輸入"/nick"的話為重命名消息
if(message.indexOf('/nick') === 0) {
var nickname_array = message.split(' ');
if(nickname_array.length >= 2) {
var old_nickname = nickname;
nickname = nickname_array[1];
var nickname_message = "用戶 " + old_nickname + " 改名為: " + nickname;
wsSend("nick_update", client_uuid, nickname, nickname_message,clients.length);
}
}//發(fā)送消息
else {
wsSend("message", client_uuid, nickname, message,clients.length);
}
});
//關(guān)閉socket連接時(shí)
var closeSocket = function(customMessage) {
//遍歷客戶端
for(var i=0; i<clients.length; i++) {
//如果客戶端存在
if(clients[i].id == client_uuid) {
// 聲明離開(kāi)信息
var disconnect_message;
if(customMessage) {
disconnect_message = customMessage;
} else {
disconnect_message = nickname + " 走了";
}
//客戶端數(shù)組中刪掉
clients.splice(i, 1);
//服務(wù)廣播消息
wsSend("notification", client_uuid, nickname, disconnect_message,clients.length);
}
}
}
ws.on('close', function() {
closeSocket();
});
process.on('SIGINT', function() {
console.log("Closing things");
closeSocket('Server has disconnected');
process.exit();
});
});
服務(wù)器端主要是接收信息,判斷是聊天信息還是重命名信息,然后發(fā)送廣播。同時(shí),當(dāng)用戶連接上服務(wù)器端或者關(guān)閉連接時(shí),服務(wù)器也會(huì)發(fā)送廣播通知其他用戶。
我們封裝了wsSend函數(shù)用來(lái)處理消息的廣播。對(duì)每個(gè)連接的用戶,我們默認(rèn)給他分配為游客。為了實(shí)現(xiàn)廣播,我們用clients數(shù)組來(lái)保存連接的用戶。
將編寫好的文件保存為server.js,在終端工具中,使用node server.js來(lái)啟動(dòng)你剛剛編寫的服務(wù)器。如果終端沒(méi)有報(bào)錯(cuò),證明你的代碼已經(jīng)正常運(yùn)行。
在實(shí)際項(xiàng)目中,服務(wù)器邏輯遠(yuǎn)遠(yuǎn)比此示例復(fù)雜得多。服務(wù)器端完成后,再來(lái)編寫客戶端代碼。
界面非常簡(jiǎn)單,我們通過(guò)兩張圖片來(lái)實(shí)現(xiàn)界面效果,首先創(chuàng)建我們的聊天界面,此項(xiàng)目中為了方便我們使用EUI進(jìn)行快速開(kāi)發(fā)。如下圖:
首先創(chuàng)建一個(gè)Image來(lái)放置我們的背景圖。
創(chuàng)建三個(gè)Label對(duì)象,一個(gè)作為title:“多人在線聊天室”,一個(gè)作為提示:“當(dāng)前在線人數(shù)”,還有一個(gè)id為lb_online的作為在線人數(shù)顯示文本。
創(chuàng)建一個(gè)EditableText對(duì)象id為input_msg作為消息發(fā)送輸入框,用戶可以在此輸入消息進(jìn)行發(fā)送。
創(chuàng)建一個(gè)Button對(duì)象id為btn_ok,點(diǎn)擊按鈕可以執(zhí)行發(fā)送消息動(dòng)作。
創(chuàng)建界面的操作和WebSocket對(duì)象創(chuàng)建動(dòng)作在同時(shí)進(jìn)行,在init方法中創(chuàng)建WebSocket對(duì)象,并執(zhí)行服務(wù)器連接操作,代碼如下:
public ws;
private init() {
/**WebSocket連接 */
this.ws = new WebSocket('ws://127.0.01:8180');
this.ws.onopen = function (e) {
console.log('Connection to server opened');
}
}
由于服務(wù)器開(kāi)放了8180端口,我們也需要使用8180端口進(jìn)行連接。當(dāng)連接成功,可執(zhí)行onopen方法。
服務(wù)器連接成功了,在控制臺(tái)打印 'Connection to server opened'。
onmessage方法中讀取服務(wù)器傳遞過(guò)來(lái)的數(shù)據(jù),并通過(guò)appendLog方法將數(shù)據(jù)顯示在對(duì)應(yīng)的文本里,
使用newLabel方法并將一條新消息插入到消息框中。
private init() {
/**WebSocket連接 */
this.ws = new WebSocket('ws://127.0.01:8180');
this.ws.onopen = function (e) {
console.log('Connection to server opened');
}
/**昵稱 */
var nickname;
var self = this;
this.ws.onmessage = function (e) {
var data = JSON.parse(e.data);
nickname = data.nickname;
appendLog(data.type, data.nickname, data.message, data.clientcount);
console.log("ID: [%s] = %s", data.id, data.message);
//插入消息
self.group_msg.addChild(self.newLabel(data.nickname, data.message))
}
function appendLog(type, nickname, message, clientcount) {
console.log(clientcount)
/**聊天信息 */
var messages = this.list_msg;
/**提示 */
var preface_label;
if (type === 'notification') {
preface_label = "提示:";
} else if (type === 'nick_update') {
preface_label = "警告:";
} else {
preface_label = nickname;
}
self.preface_label = preface_label;
var message_text = self.message_text = message;
/**在線人數(shù) */
self.lb_online.text = clientcount;
}
/**點(diǎn)擊OK發(fā)送 */
this.btn_ok.addEventListener(egret.TouchEvent.TOUCH_TAP, this.sendMessage, this);
}
private newLabel(name: string, msg: string) {
var label1: eui.Label = new eui.Label();
label1.text = name + ":" + msg;
label1.textColor = 0x000000
return label1;
}
最后我們來(lái)編寫發(fā)送消息的函數(shù),在btn_ok中egret.TouchEvent.TOUCH_TAP點(diǎn)擊之后的相應(yīng)函數(shù)為sendMessage方法。
/**發(fā)送消息 */
private sendMessage() {
var message = this.input_msg.text;
if (message.length < 1) {
// console.log("不能發(fā)送空內(nèi)容!");
return;
}
this.ws.send(message);
/**清空輸入框內(nèi)容 */
this.input_msg.text = "";
}
如果輸入框中內(nèi)容不為空的話就將數(shù)據(jù)通過(guò) this.ws.send(message); 發(fā)送給服務(wù)器,并清除輸入框的內(nèi)容。
最終運(yùn)行后,我們就可以實(shí)現(xiàn)多人在線聊天功能了。
完整版代碼如下:
class Chat extends eui.Component implements eui.UIComponent {
/**在線人數(shù)文本 */
public lb_online: eui.Label;
/**聊天窗口 */
public scr_msg: eui.Scroller;
/**聊天信息 */
public list_msg: eui.List;
/**輸入框 */
public input_msg: eui.EditableText;
/**確定按鈕 */
public btn_ok: eui.Button;
/**聊天窗口消息組 */
public group_msg: eui.Group;
public constructor() {
super();
}
protected partAdded(partName: string, instance: any): void {
super.partAdded(partName, instance);
}
protected childrenCreated(): void {
this.init();
super.childrenCreated();
}
/**WebSocket */
public ws;
public preface_label;
public message_text;
private init() {
/**WebSocket連接 */
//線上測(cè)試鏈接,服務(wù)端代碼需在服務(wù)器啟動(dòng)
//this.ws = new WebSocket('ws://7hds.com:8180');
this.ws = new WebSocket('ws://127.0.01:8180');
this.ws.onopen = function (e) {
console.log('Connection to server opened');
}
/**昵稱 */
var nickname;
var self = this;
this.ws.onmessage = function (e) {
var data = JSON.parse(e.data);
nickname = data.nickname;
appendLog(data.type, data.nickname, data.message, data.clientcount);
console.log("ID: [%s] = %s", data.id, data.message);
//插入消息
self.group_msg.addChild(self.newLabel(data.nickname, data.message))
}
function appendLog(type, nickname, message, clientcount) {
console.log(clientcount)
/**聊天信息 */
var messages = this.list_msg;
/**提示 */
var preface_label;
if (type === 'notification') {
preface_label = "提示:";
} else if (type === 'nick_update') {
preface_label = "警告:";
} else {
preface_label = nickname;
}
self.preface_label = preface_label;
var message_text = self.message_text = message;
/**在線人數(shù) */
self.lb_online.text = clientcount;
}
/**點(diǎn)擊OK發(fā)送 */
this.btn_ok.addEventListener(egret.TouchEvent.TOUCH_TAP, this.sendMessage, this);
}
/**發(fā)送消息 */
private sendMessage() {
var message = this.input_msg.text;
if (message.length < 1) {
// console.log("不能發(fā)送空內(nèi)容!");
return;
}
this.ws.send(message);
/**清空輸入框內(nèi)容 */
this.input_msg.text = "";
// console.log(this.ws.bufferedAmount);
}
private newLabel(name: string, msg: string) {
var label1: eui.Label = new eui.Label();
label1.text = name + ":" + msg;
label1.textColor = 0x000000
return label1;
}
}
本文的demo增加了客戶端與服務(wù)器的互動(dòng),同時(shí)也實(shí)現(xiàn)了客戶端之間的聯(lián)系。
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。