In nodejs, the HTTP protocol and WS protocol are reused on the same port.

00. Foreword

​ I am writing a web page recently, which requires the use of the back-end websocket service. Since it does not require too complex functions, the back-end chooses to use the nodejs nodejs-websocketmodule. During the development process, I found that the http service was also needed, but nodejs-websocketthe http service could not be implemented, so I began to look for a way to solve the problem of two protocols sharing the same port.

01. Related issues

Generally speaking, each service needs to occupy a port when it is started. For example, as mentioned above nodejs-websocket, the following code is shown (code source: nodejs-websocket):

const ws = require("nodejs-websocket")
 
const server = ws.createServer(function (conn) {
    
    
    console.log("New connection")
    conn.on("text", function (str) {
    
    
        console.log("Received "+str)
        conn.sendText(str.toUpperCase()+"!!!")
    })
    conn.on("close", function (code, reason) {
    
    
        console.log("Connection closed")
    })
}).listen(8001)

​Run the above code to open a websocket service and listen on 8001the port.

​ If you run another http service at this time, for example express, if the same listening 8001port is used, a port conflict will occur, such as the following code (code source: expressChinese website ):

const express = require('express')
const app = express()
const port = 8001

app.get('/', (req, res) => {
    
    
  res.send('Hello World!')
})

app.listen(port, () => {
    
    
  console.log(`Example app listening at http://localhost:${
      
      port}`)
})

​ If you run the above two services at the same time, an error message will appear Error: listen EADDRINUSE: address already in use :::8001.

If you don’t quite understand the meaning or use of ports, you can refer to computer network related books. Briefly speaking, a port is used in computer communication to mark a service or application so that the transport layer knows which application in the application layer to send a certain data packet to.

​ The above starts two services, and these two services are independent and listen to the same port at the same time. At this time, a port conflict will occur.

02. How to implement reuse ports

​ When the client initiates a websocket connection, the client will send an http request to the browser. The request header of the request contains and, and Connection:Upgraderequests Upgrade:websocketthe server to modify the protocol to websocket. If the server agrees to modify the protocol, it will respond with a response code of 101 HTTP message. At this point, the responsibilities of HTTP have been completed, and the following communication will use the websocket protocol. (Note: The websocket protocol will only be used when the client uses an instantiated websocket instance to transmit data. During this period, the client can still initiate other http requests, and the two do not conflict).

​ It can be concluded that you only need to let the http service handle all requests, and switch to the websocket service when encountering a request. At this time, only the http listening port is needed, and the websocket does not need to be externally monitored, but is forwarded directly by the http service Connection:Upgrade.Upgrade:websocket

​The following is the code that uses expressthe , http, and wsmodules to implement "reuse" ports:

const express = require("express");
const WS_MODULE = require("ws");
const http = require("http");

const app = express();
const port = 80;

app.get("/hello", (req, res) => {
    
    
  res.send("hello world");
});

const server = http.createServer(app);
ws = new WS_MODULE.Server({
    
     server });

ws.on("connection", (conn) => {
    
    
  conn.on("message", (str) => {
    
    
      //handle received message
  });
});

server.listen(port, () => {
    
    
  console.log("服务器已开启,端口号:" + port);
});

In the above code, the application can provide websocket and http services at the same time, and any request path under the domain name will be processed in the same way when the protocol is switched to websocket. That is: there is no difference between concatenating ws://localhostand in this case .ws://localhost/walekj/awe/dacz

​ If you want to use different websocket services for different websocket request paths, you can use the following code:

const express = require("express");
const WS_MODULE = require("ws");
const http = require("http");

const app = express();
const port = 80;

app.get("/hello", (req, res) => {
    
    
  res.send("hello world");
});

const server = http.createServer(app);

const chatWS = new WS_MODULE.Server({
    
     noServer: true }); //这里采用noServer
chatWS.on("connection", (conn) => {
    
    
  console.log("新的客户端连接 chatWS进行处理");
});

const fileWS = new WS_MODULE.Server({
    
     noServer: true }); //这里采用noServer
fileWS.on("connection", (conn) => {
    
    
  console.log("新的客户端连接 fileWS进行处理");
});

server.on("upgrade", (req, socket, head) => {
    
    
  if (req.url === "/chat") {
    
    
    //由chatWS 进行处理
    chatWS.handleUpgrade(req, socket, head, (conn) => {
    
    
      chatWS.emit("connection", conn, req);
    });
  } else if (req.url === "/file") {
    
    
    //由fileWS 进行处理
    fileWS.handleUpgrade(req, socket, head, (conn) => {
    
    
      fileWS.emit("connection", conn, req);
    });
  } else {
    
    
    //直接关闭连接
    socket.destroy();
  }
});

server.listen(port, () => {
    
    
  console.log("服务器已开启,端口号:" + port);
});

ws://localhost/chat​ and can now be connected ws://localhost/file, while other URIs cannot be connected.

​ Using this method, you can do other things before connecting, such as user authentication

03. Reference link&&API

ws

express

http

Guess you like

Origin blog.csdn.net/qq_44856695/article/details/120250286