欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

利用Socket.io 實(shí)現(xiàn)消息實(shí)時(shí)推送功能

 更新時(shí)間:2017年12月04日 11:08:16   作者:noiron  
這篇文章主要介紹了利用Socket.io 實(shí)現(xiàn)消息實(shí)時(shí)推送功能,需要的朋友可以參考下

項(xiàng)目背景介紹

最近在寫的項(xiàng)目中存在著社交模塊,需要實(shí)現(xiàn)這樣的一個(gè)功能:當(dāng)發(fā)生了用戶被點(diǎn)贊、評(píng)論、關(guān)注等操作時(shí),需要由服務(wù)器向用戶實(shí)時(shí)地推送一條消息。最終完成的項(xiàng)目地址為:https://github.com/noiron/socket-message-push,這里將介紹一下實(shí)現(xiàn)的思路及部分代碼。

項(xiàng)目的流程中存在著這樣的幾個(gè)對(duì)象:

  • 用 Java 實(shí)現(xiàn)的后端服務(wù)器
  • 用 Node.js 實(shí)現(xiàn)的消息推送服務(wù)器
  • 用戶進(jìn)行操作的客戶端

事件處理的流程如下:

  • 用戶進(jìn)行點(diǎn)贊操作時(shí),后端服務(wù)器會(huì)進(jìn)行處理,并向 Node.js 消息推送服務(wù)器發(fā)送一條消息
  • Node.js 消息推送服務(wù)器接收到后端發(fā)送的消息后,處理數(shù)據(jù),并確定向哪個(gè)用戶進(jìn)行推送
  • 用戶的客戶端接收到由 Node.js 服務(wù)器推送來的消息后,即可進(jìn)行通知的顯示。
  • 上面的流程中,Java 后端服務(wù)器是如何實(shí)現(xiàn)的不在此篇文章的討論范圍內(nèi),本文將主要介紹如何使用 Node.js 來實(shí)現(xiàn)這個(gè)消息推送服務(wù)器。

考慮消息推送服務(wù)器上必須記錄下當(dāng)前在線用戶的信息,這樣才能向特定的用戶推送消息。所以當(dāng)用戶登錄時(shí),必須將自身的用戶信息發(fā)到 Node.js 服務(wù)器上。為了達(dá)到這種雙向的實(shí)時(shí)消息傳遞,很明顯地考慮用 WebSocket 來實(shí)現(xiàn)。既然我們在消息推送服務(wù)器上使用了 Node.js,我們就有了一個(gè)很方便的選項(xiàng):socket.io。

Socket.io 介紹

Socket.io是一個(gè)用 JavaScript 實(shí)現(xiàn)的實(shí)時(shí)雙向通信的庫,利用它來實(shí)現(xiàn)我們的功能會(huì)很簡單。

socket.io 包含兩個(gè)部分:

  • 服務(wù)器端(server):運(yùn)行在 Node.js 服務(wù)器上
  • 客戶端(client):運(yùn)行在瀏覽器中

可以看看如下的 socket.io 的示例代碼,它給出了 socket.io 發(fā)出及監(jiān)聽事件的基本用法:

io.on('connection', function(socket){
 socket.emit('request', /* */); // emit an event to the socket
 io.emit('broadcast', /* */); // emit an event to all connected sockets
 socket.on('reply', function(){ /* */ }); // listen to the event
});

關(guān)于 Socket.io 還有一點(diǎn)需要注意:Socke.io 并不完全是 WebSocket 的實(shí)現(xiàn)。

Note: Socket.IO is not a WebSocket implementation. Although Socket.IO indeed uses WebSocket as a transport when possible, it adds some metadata to each packet: the packet type, the namespace and the ack id when a message acknowledgement is needed.
接下來我們需要用 Express.js 來建立一個(gè)服務(wù)器端程序,并在其中引入 Socket.io。

Node.js 服務(wù)器的搭建

利用 Express.js 搭建基礎(chǔ)服務(wù)器

我們使用了 Express.js 來搭建 Node.js 消息推送服務(wù)器,先利用一個(gè)簡要的例子來瀏覽其功能:

// server.js
const express = require('express');
const app = express();
const path = require('path');
const http = require('http').Server(app);
const port = 4001;
app.use(express.static(path.join(__dirname, 'public')));
app.get('/', function(req, res) {
 res.sendFile(__dirname + '/public/index.html');
});
app.get('/api', function(req, res) {
 res.send('.');
});
http.listen(port, function() {
 console.log(`listening on port:${port}`);
});

將上面的代碼保存為 server.js,新建一個(gè) public 文件夾,在其中放入 index.html 文件。運(yùn)行以下命令:

node server.js

現(xiàn)在即可在 localhost:4001 查看效果了。

引入 Socket.io

現(xiàn)在已經(jīng)有了一個(gè)基礎(chǔ)的 Express 服務(wù)器,接下來需要將 Socket.io 加入其中。

const io = require('socket.io')(http);
io.on('connection', function(socket) {
 console.log('a user connected');
 socket.broadcast.emit('new_user', {});
}

這里的 io 監(jiān)聽 connection 事件,當(dāng) client 與 server 建立了連接之后,這里的回調(diào)函數(shù)會(huì)被調(diào)用( client中的代碼將在下一節(jié)介紹)。

函數(shù)的參數(shù) socket 代表的是當(dāng)前的 client 和 server 間建立的這個(gè)連接??稍?client 程序中將這個(gè)建立的 socket 連接打印出來,如下圖所示:

其中的 id 屬性可以用于標(biāo)識(shí)出這一連接,從而 server 可以向特定的用戶發(fā)送消息。

socket.broadcast.emit('new_user', {});

這一行代碼表示 socket 將向當(dāng)前所有與 server 建立了連接的 client(不包括自己) 廣播一條名為 new_user 的消息。

后端推送消息的處理流程

  • 在 Node 服務(wù)器建立一個(gè)用戶信息和 socket id 的映射表,因?yàn)橥挥脩艨赡艽蜷_了多個(gè)頁面,所以他的 socket id 可能存在多個(gè)值。當(dāng)用戶建立連接時(shí),往其中添加值;用戶斷開連接后,刪除相應(yīng)值。
  • 當(dāng) Java 后臺(tái)存在需要推送的消息時(shí),會(huì)向 Node 服務(wù)器的 /api 路徑 post 一條消息,其中包括用于標(biāo)識(shí)用戶的 tokenId 和其它數(shù)據(jù)。
  • Node 服務(wù)器接收到 post 請(qǐng)求后,對(duì)請(qǐng)求內(nèi)容進(jìn)行處理。根據(jù) tokenId 找出與該用戶對(duì)應(yīng)的 socket id,socket.io 會(huì)根據(jù) id 來向用戶推送消息。

對(duì)用戶信息的處理

方便起見,這里只用一個(gè)數(shù)組保存用戶信息,實(shí)際工作中可以根據(jù)需要放入數(shù)據(jù)庫中保存。

global.users = []; // 記錄下登錄用戶的tokenId, socketId

當(dāng)用戶登錄時(shí), client 會(huì)向 server 發(fā)送 user_login 事件,服務(wù)器接收到后會(huì)做如下操作:

socket.on('user_login', function(info) {
 const { tokenId, userId, socketId } = info;
 addSocketId(users, { tokenId, socketId, userId });
});

addSocketId() 會(huì)向 users 數(shù)組中添加用戶信息,不同用戶通過 tokenId 進(jìn)行區(qū)分,每個(gè)用戶有一個(gè) socketIds 數(shù)組,保存可能存在的多個(gè) socketId。該函數(shù)的具體代碼可見 src/utils.js 文件。

同理,還有一個(gè) deleteSocketId() 函數(shù)用于刪除用戶信息,代碼可見同一文件。

在獲取了用戶的 tokenId 之后,就需要找到對(duì)應(yīng)的 socketId,然后向特定用戶推送消息。

// 只向 id = socketId 的這一連接發(fā)送消息 
io.sockets.to(socketId).emit('receive_message', {
 entityType,
 data
});

服務(wù)器的思路大致如此,接下來介紹客戶端中是如何進(jìn)行相應(yīng)的處理的。

客戶端

Socket.io 的初始化

首先在 html 文件中引入 Socket.io 的 client 端文件,例如通過 CDN 引入:

<script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/2.0.3/socket.io.js"></script>

其它的引入方式:

<script src="/socket.io/socket.io.js"></script>
const io = require('socket.io-client');
// or with import syntax
import io from 'socket.io-client';

引入 Socket.io 后就獲得了 io 函數(shù),通過它來與消息推送服務(wù)器建立連接。

// 假設(shè)你將 Node 服務(wù)器部署后的地址為:https://www.example.com/ws
// 則: WS_HOST = 'https://www.example.com'
const msgSocket = io(`${WS_HOST}`, {
 secure: true,
 path: '/ws/socket.io'
});

如果監(jiān)聽本地:

const msgSocket = io('http://localhost:4001');

這里如果寫成 io('https://www.example.com/ws') 會(huì)出現(xiàn)錯(cuò)誤,需要將 /ws 寫入path中。

為了能在其它文件使用這一變量,可將 msgSocket 作為一個(gè)全局變量:

window.msgSocket = msgSocket;

用戶建立連接

// 用戶登錄時(shí),向服務(wù)器發(fā)送用戶的信息。服務(wù)器會(huì)在收到信息后建立 socket 與用戶的映射。
msgSocket.emit('user_login', {
 userId,
 socketId: msgSocket.id,
 tokenId
});

接收到推送的消息后的處理

// WebSocket 連接建立后,監(jiān)聽名為 receive_message 的事件 
msgSocket.on('receive_message', msg => {
 store.dispatch({
  type: 'NEW_SOCKET_MSG',
  payload: msg
 });
});

當(dāng) WebSocket 服務(wù)器向客戶端推送了消息之后,客戶端需要監(jiān)聽 receive_message 事件,接收到的參數(shù)中有相應(yīng)待處理的信息。

由于使用了 Redux 進(jìn)行數(shù)據(jù)的處理,所以這里 dispatch 了一個(gè) NEW_SOCKET_MSG action,后續(xù)則是常規(guī)的 redux 處理流程了。

項(xiàng)目的使用

GitHub 上的項(xiàng)目地址:https://github.com/noiron/socket-message-push

npm run dev

即可在 devlopment 環(huán)境下進(jìn)行測試,現(xiàn)在你就有了一個(gè)運(yùn)行在4001端口的消息推送服務(wù)器了。

但是這里并沒有后端的服務(wù)器來向我們發(fā)送消息,所以我們將利用 Postman 來模擬發(fā)送消息。

為了展示程序的功能,在項(xiàng)目的 client 文件夾下放置了一個(gè) index.html 文件。注意這個(gè)文件并不能用在實(shí)際的項(xiàng)目中,只是用來顯示消息推送的效果而已。

在開啟了服務(wù)器之后,打開 client/index.html,根據(jù)提示隨意輸入一個(gè) tokenId 即可。

現(xiàn)在利用 Postman 向 localhost:4001/api post 如下的一條信息:

{ 
 // tokens 數(shù)組表示你想向哪個(gè)用戶推送消息
 "tokens": ["1", "2"], 
 "data": "You shall not pass!!!"
}

至此,如果一切順利,你應(yīng)該能夠在 client 的控制臺(tái)中看到收到的消息了。

你可以打開多個(gè) client 頁面,輸入不同的 tokenId,然后檢查消息是否發(fā)送給了正確的用戶。

總結(jié)

以上所述是小編給大家介紹的利用Socket.io 實(shí)現(xiàn)消息實(shí)時(shí)推送功能,希望對(duì)大家有所幫助,如果大家有任何疑問請(qǐng)給我留言,小編會(huì)及時(shí)回復(fù)大家的。在此也非常感謝大家對(duì)腳本之家網(wǎng)站的支持!

相關(guān)文章

  • IDEA中切換不同版本的JDK的詳細(xì)教程(超管用)

    IDEA中切換不同版本的JDK的詳細(xì)教程(超管用)

    這篇文章主要介紹了IDEA中切換不同版本的JDK的詳細(xì)教程(超管用),本文通過步驟詳解給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-09-09
  • Java并發(fā)編程之對(duì)象的組合

    Java并發(fā)編程之對(duì)象的組合

    這篇文章主要介紹了Java并發(fā)編程之對(duì)象的組合,文章基于Java的相關(guān)資料展開主題內(nèi)容,具有一定的參考價(jià)值,需要的小伙伴可以參考一下
    2022-04-04
  • 單元測試 @mock與@SpringBootTest的使用

    單元測試 @mock與@SpringBootTest的使用

    這篇文章主要介紹了單元測試 @mock與@SpringBootTest的使用方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-10-10
  • Java正則表達(dá)式如何匹配特定html標(biāo)簽內(nèi)的內(nèi)容

    Java正則表達(dá)式如何匹配特定html標(biāo)簽內(nèi)的內(nèi)容

    這篇文章主要給大家介紹了關(guān)于Java正則表達(dá)式如何匹配特定html標(biāo)簽內(nèi)的內(nèi)容的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-09-09
  • Java如何用時(shí)間戳重命名上傳的文件

    Java如何用時(shí)間戳重命名上傳的文件

    這篇文章主要介紹了Java如何用時(shí)間戳重命名上傳的文件問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2024-04-04
  • 安裝多個(gè)版本JDK后使用時(shí)的切換方法總結(jié)

    安裝多個(gè)版本JDK后使用時(shí)的切換方法總結(jié)

    我們平時(shí)在window上做開發(fā)的時(shí)候,可能需要同時(shí)開發(fā)兩個(gè)甚至多個(gè)項(xiàng)目,有時(shí)不同的項(xiàng)目對(duì)JDK的版本要求有區(qū)別,下面這篇文章主要給大家介紹了安裝多個(gè)版本JDK后使用的切換方法,需要的朋友可以參考借鑒,下面來一起看看吧。
    2017-01-01
  • java 算法之歸并排序詳解及實(shí)現(xiàn)代碼

    java 算法之歸并排序詳解及實(shí)現(xiàn)代碼

    這篇文章主要介紹了java 算法之歸并排序詳解及實(shí)現(xiàn)代碼的相關(guān)資料,需要的朋友可以參考下
    2017-03-03
  • spring異步service中處理線程數(shù)限制詳解

    spring異步service中處理線程數(shù)限制詳解

    這篇文章主要給大家介紹了關(guān)于spring異步service中處理線程數(shù)限制的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用spring具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-09-09
  • Java實(shí)現(xiàn)雪花算法的示例代碼

    Java實(shí)現(xiàn)雪花算法的示例代碼

    SnowFlow算法是Twitter推出的分布式id生成算法,主要核心思想就是利用64bit的long類型的數(shù)字作為全局的id。本文將用Java語言實(shí)現(xiàn)雪花算法,感興趣的可以學(xué)習(xí)一下
    2022-03-03
  • FF瀏覽器和IE下載文件亂碼問題的解決方法

    FF瀏覽器和IE下載文件亂碼問題的解決方法

    大家可以看到如下截圖,下載文件出現(xiàn)了亂碼,在其他瀏覽器(IE,Chrome....)上沒有出現(xiàn)這個(gè)問題,解決方法很簡單,遇到類似問題的朋友可以了解下哦
    2013-08-08

最新評(píng)論