[技術筆記]在NodeJS中使用socket.io, 或者ws

websocket在NodeJS和Vue中的簡單應用

Posted by 李定宇 on Tuesday, January 31, 2023

WebSocket in NodeJS and VueJS

Websocket簡介

根據wiki的定義,websocket是一個基於TCP的網路傳輸協定。在一般的 GET/POST http request中,是等傳輸完資料後、TCP會經過四次揮手後斷開連接;但在WebSocket協定中,只要客戶端和服務端經過TCP握手連接後,兩者就可以建立長時間的連接。

為何要有websocket的協定呢?主要是因為HTTP協議的缺陷:HTTP請求只能由客戶端發起。這樣一來,如果客戶端需要響應服務端的變化,就必須要在一個間隔時間內不斷發起請求、「監聽」服務端的變化;而有了websocket,便可以建立了長時間的連接:客戶端發起一次請求、建立連接,而後只要服務端有數據或是什麼的變化,服務端便可以透過該連接直接傳遞、客戶端進而響應該變化。

在NodeJS中使用websocket

Awesome List of websocket for NodeJS可以看到,NodeJS有許多websocket的依賴;然後根據starts數來排名的話,socket.iowebsockets/ws與其他依賴有著很大的差距(57.5k and 19.4k on 20230131),因此先以這兩者和exporess來Demo看看。

  • Socket.io

    // app.js
    const express = require('express')
    const http = require('http')
    const socket = require('socket.io')
    
    const app = express()
    // use express to handle http server
    const server = http.createServer(app) 
    const io = socket(server)
    
    // while socket connect, send a 'hello world text' 
    const onConnection = (socket) => {
    	socket.send("hello world ")
    	console.log('Socket.io init success')
    }
    io.on("connection", onConnection)
    
    server.listen(3000, () => {
    console.log('Server listening at port 3000');
    })
    
  • ws

    // app.js
    
    const express = require('express')
    const { WebSocketServer } = require('ws')
    
    const app = express()
    // use express to handle http server
    const server = http.createServer(app) 
    
    const wss = new WebSocketServer({ server })
    
    wss.on('connection', ws => {
    	ws.send("hello world ")
    	console.log('Socket.io init success')
    })
    server.listen(3000, () => {
    console.log('Server listening at port 3000');
    })
    
    

可以看到,兩者在NodeJS的寫法上是沒有太大的區別,差別應該是在包的體積大小和性能方面。(socket.io: 276.6k, ws:43.8K)

在前端使用Websocket(以Vue為例)

  • Socket.io

Socket.io之前最吸引人的地方,就是它在服務端和瀏覽器端都有做封裝,因此可以直接拿來用:

// useSocket.ts

import { io } from 'socket.io-client'

export default function useSocket() {
    const socket = io('ws://localhost:3000')
    return {
        socket,
    }
}
// Demo.vue
import useSocket from '../utils/useSocket'
...
setup(){
	const { socket } = useSocket()
    onMounted(() => {
	    socket.on('connect', (data) => {
	        console.log(data)
	    })
	})
	return {}
}
  • ws

從官方文件和網路上其他人的Demo來看,目前ws還沒有封裝客戶端的使用,所以只能用瀏覽器原生的 WebSocket來做封裝;最簡單的話就是直接拿原生API來用

// useSocket.ts
export default function useSocket() {
    const socket = new WebSocket('ws://localhost:3000')
    return {
        socket,
    }
}
// Demo.vue
import useSocket from '../utils/useSocket'
...
setup(){
	const { socket } = useSocket()
    onMounted(() => {
    	socket.onmessage( (event) =>{
    		console.log(`socket data:${event.data}`)
    	} )
	})
	return {}
}

ChangeLog

  • 20230131-初稿