JavaScript?WebSocket實(shí)現(xiàn)實(shí)時(shí)雙向聊天
軟件要做一個(gè)聊天功能,一般來(lái)說(shuō)是要接入其他的接口,但是因?yàn)樽约褐奥?tīng)說(shuō)過(guò)沒(méi)用過(guò)WebSocket,所以打算帶薪摸魚(yú),好好的研究一下WebSocket。
一、搭建WebSocket服務(wù)器
我軟件后端使用的nodejs,所以我們這次也用nodejs來(lái)做后端,方便之后的接入
1、搭建服務(wù)器
我們先引入ws庫(kù)和http庫(kù),把WebSocket服務(wù)搭建起來(lái)
const WebSocket = require('ws'); const http = require('http'); const url = require('url'); const server = http.createServer((req, res) => { res.writeHead(200); res.end('WebSocket server is running.'); });
2、初始化WebSocket服務(wù)器
我們需要將WebSocket服務(wù)綁定到我們的http服務(wù)器上
const wss = new WebSocket.Server({ server });
3、客戶(hù)映射
使用Map的數(shù)據(jù)結(jié)構(gòu)來(lái)存儲(chǔ)以連接的用戶(hù)及其對(duì)應(yīng)的客戶(hù)端
const connectedUsers = new Map();
4、事件處理
連接事件
因?yàn)槲覀兊牧奶焓菃螌?duì)單的,而WebSocket是廣播(一對(duì)多)傳輸?shù)?,所以我們可以使用UserA和UserB的用戶(hù)名來(lái)做成連接,只有UserA和UserB進(jìn)入此聊天室。
wss.on('connection', (ws, req) => { const query = url.parse(req.url, true).query; const userIdA = query.userA; const userIdB = query.userB; connectedUsers.set(userIdA, ws); connectedUsers.set(userIdB, ws); // 這里添加其他邏輯,比如我這里是將UserA和UserB從URL里面分離,并且將ID和Web socket客戶(hù)端關(guān)聯(lián)起來(lái),這里也可以做一下用戶(hù)認(rèn)證之類(lèi)的操作 });
關(guān)閉事件
關(guān)閉事件是指的有用戶(hù)斷開(kāi)連接時(shí),就從映射中移除用戶(hù)相應(yīng)的ID
ws.on('close', () => { console.log(`Connection closed for users ${userIdA} and ${userIdB}.`); connectedUsers.delete(userIdA); connectedUsers.delete(userIdB); });
錯(cuò)誤事件
這里就是記錄了在連接期間發(fā)生的任何錯(cuò)誤
ws.on('error', (message) => { console.error(`Error occurred for users ${userIdA} and ${userIdB}:`, err); });
消息接收
這個(gè)事件就是在連接過(guò)程中用戶(hù)在廣播中發(fā)送的消息,我們將他解析成JSON內(nèi)容(因?yàn)槲疫@里做的單對(duì)單,所以數(shù)據(jù)中包含了sender、receiverID、content,可以使用這種方式來(lái)查找接受者,并且將消息廣播給接受者)
ws.on('message', (message) => { const dataMessage = message.toString() const data = JSON.parse(dataMessage)[0] const senderId = data.sender; const receiverId = data.receiverID; const content = data.content; // 廣播消息給接收方 const receiverWs = connectedUsers.get(receiverId); if (receiverWs) { receiverWs.send(JSON.stringify({ sender: senderId, content, receiver:receiverId })); } else { console.warn(`Receiver ${receiverId} is not connected.`); } });
5、WebSocket!啟動(dòng)!
最后,我們只要制定監(jiān)聽(tīng)端口,啟動(dòng)WebSocket服務(wù)器即可
server.listen(3000, () => { console.log('WebSocket server listening on port 3000.'); });
二、前端uniapp應(yīng)用
我這里使用uniapp制作了一個(gè)基礎(chǔ)的分屏,左邊模擬a用戶(hù),右邊模擬b用戶(hù)
左邊使用messageA來(lái)存儲(chǔ)消息,右邊使用messageB來(lái)存儲(chǔ)消息(其實(shí)也可以把他們兩個(gè)合成一個(gè),但是這里是分屏演示,如果合成一個(gè)那么即時(shí)通訊的功能就不太顯著了)
<template> <view class="content"> <view class="a"> <view class="text"> <div v-for="(item, index) in messagesA" :key="index"> {{item.sender}}:{{item.content}} </div> </view> <input class="input" type="text" placeholder="請(qǐng)輸入文本" @input="inputa" :value="inputaV" /> <button @click="sumA">發(fā)送</button> </view> <view class="b"> <view class="text"> <div v-for="(item, index) in messagesB" :key="index"> {{item.sender}}:{{item.content}} </div> </view> <input class="input" type="text" placeholder="請(qǐng)輸入文本" @input="inputb" :value="inputbV" /> <button @click="sumB">發(fā)送</button> </view> </view> </template>
data() { return { inputaV: '',//a用戶(hù)輸入 inputbV: '',//b用戶(hù)輸入 messagesA:[],//a用戶(hù)的消息列表 messagesB: [],//b用戶(hù)的消息列表 url: 'ws://127.0.0.1:3000',//使用ws連接連接到webSocket服務(wù)器 socket: null,//socket實(shí)例 userA: 'a',//a用戶(hù)的id userB: 'b',//b用戶(hù)的id } },
//初始化,在進(jìn)入軟件后便處理url連接,將a用戶(hù)和b用戶(hù)的id放入到url連接中(此方法在初始化頁(yè)面的時(shí)候就要進(jìn)行調(diào)用) //并且在兩個(gè)用戶(hù)連接到服務(wù)器中綁定消息的回調(diào)函數(shù),使得有任意一個(gè)用戶(hù)發(fā)送消息之后都會(huì)接受到消息 enter() { let url = `${this.url}?userA=${this.userA}&userB=${this.userB}`; this.connect(url); uni.onSocketMessage(this.onSocketMessage()); // 綁定消息接收回調(diào) }, //連接方法,此方法是在用戶(hù)在進(jìn)入頁(yè)面中就調(diào)用的,讓兩個(gè)用戶(hù)連接到websocket服務(wù)器中 connect(url) { this.socket = uni.connectSocket({ url, success() { console.log('WebSocket連接成功'); uni.onSocketOpen(() => { console.log('WebSocket連接已打開(kāi)!'); }); }, fail(err) { console.error('WebSocket連接失敗', err); } }); }, //用戶(hù)a發(fā)送消息的事件 sumA() { if (this.socket) { //將消息中帶上發(fā)出人,接收人,確保信息無(wú)誤 this.messagesA.push({ sender: this.userA, content: this.inputaV, receiverID: this.userB }) let data = JSON.stringify(this.messagesA) uni.sendSocketMessage({ data }); this.inputaV = '' } else { console.log('連接失敗'); } }, //用戶(hù)b發(fā)送消息的事件 sumB() { if (this.socket) { this.messagesA.push({ sender: this.userB, content: this.inputbV, receiverID: this.userA }) let data = JSON.stringify(this.messagesA) uni.sendSocketMessage({ data }); this.inputbV = '' } else { console.log('連接失敗'); } }, //獲取消息事件,在任意用戶(hù)發(fā)送消息之后,前端可以監(jiān)聽(tīng)到消息的接受,我們只需要將數(shù)據(jù)進(jìn)行處理即可 //因?yàn)橛脩?hù)的顯示是用的messageA/messageB,所以我們可以通過(guò)不同的接收人來(lái)對(duì)不同的數(shù)據(jù)進(jìn)行處理 onSocketMessage(res) { let data = JSON.parse(res.data) let sender = data.sender let content = data.content let receiver = data.receiver if(receiver == this.userA){ this.messagesA.push({ sender, content, receiverID }) }else if(receiver == this.userB){ this.messagesB.push({ sender, content, receiverID }) } },
總結(jié)
到此基礎(chǔ)的一個(gè)websocket服務(wù)器的搭建和使用就完成了,WebSocket對(duì)于后端的要求和對(duì)于前后端的緊密聯(lián)系都是十分重要的,本文只是一個(gè)小的實(shí)驗(yàn)和想法,如果有不對(duì)的地方請(qǐng)指正
以上就是JavaScript WebSocket實(shí)現(xiàn)實(shí)時(shí)雙向聊天的詳細(xì)內(nèi)容,更多關(guān)于JavaScript WebSocket雙向聊天的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
JavaScript對(duì)象_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理
這篇文章主要為大家詳細(xì)介紹了JavaScript對(duì)象的相關(guān)資料,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-06-06js一維數(shù)組、多維數(shù)組和對(duì)象的混合使用方法
這篇文章主要介紹了js一維數(shù)組、多維數(shù)組和對(duì)象的混合使用方法,需要的朋友可以參考下2016-04-04js接收并轉(zhuǎn)化Java中的數(shù)組對(duì)象的方法
下面小編就為大家?guī)?lái)一篇js接收并轉(zhuǎn)化Java中的數(shù)組對(duì)象的方法。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2016-08-08微信小程序生成海報(bào)分享朋友圈的實(shí)現(xiàn)方法
利用微信強(qiáng)大的社交能力通過(guò)小程序達(dá)到裂變的目的,拉取新用戶(hù)。下面小編給大家?guī)?lái)了微信小程序生成海報(bào)分享朋友圈的實(shí)現(xiàn)方法,感興趣的朋友跟隨小編一起看看吧2019-05-05