web通讯的四种方式,常规轮询、长轮询(comet)、长连接(SSE)、WebSocket

240 阅读2分钟

web通讯的四种方式,常规轮询、长轮询(comet)、长连接(SSE)、WebSocket

常规轮询

  • 客户端
const axios = require("axios")

setInterval(function(){
if(data.data){
        clearInterval(dataSet)
        return
    }
    axios({
        method: 'GET',
        url: 'api/users/list',
    })
    .then(function (response) {
            console.log(response);
        })
        .catch(function (error) {
            console.log(error);
        });
},1000)
  • 服务端
const koa = require('koa')
const koaRouter = require('@koa/router')

const app = new koa()
const userRouter = new koaRouter({ prefix: '/users' })

userRouter.get('/list', async (ctx, next) => {
  console.log(ctx.header);
  async function delay(time) {
    return new Promise((resolve) => {
      setTimeout(() => {
        resolve()
        let num = Math.floor(Math.random() * 100)
        if (num < 30) {

          ctx.body = [
            { name: 'why', age: 18, score: 99 },
            { name: 'kobe', age: 30, score: 60 },
            { name: 'wi', age: 90, score: 23 },

          ]
        } else {
          ctx.body = ''
        }

      }, time)
    })
  }
  await delay(300)



}),
  app.use(userRouter.routes())
app.listen('9000', '0.0.0.0', () => {
  console.log('api服务器启动');
})  

长轮询

  • 客户端
const axios = require("axios")
async function subscribe() {
    let response = await axios({
        method: 'GET',
        url: 'api/users/list',
    })
    if (response.status == 502) {
        // 状态 502 是连接超时错误,
        // 连接挂起时间过长时可能会发生,
        // 远程服务器或代理会关闭它
        // 让我们重新连接
        await subscribe();
    } else if (response.status != 200) {
        // 一个 error —— 让我们显示它
        console.log(response.statusText);
        // 一秒后重新连接
        await new Promise(resolve => setTimeout(resolve, 1000));
        await subscribe();
    } else {
        // 获取并显示消息
        let message = await response.data;
        console.log(message);
        // 再次调用 subscribe() 以获取下一条消息
        await subscribe();
    }
}
subscribe();

长连接(SSE)

一般提供timeout

WebSocket

允许服务端主动向客户端推送数据。在 WebSocket API 中,浏览器和服务器只需要完成一次握手,两者之间就直接可以创建持久性的连接,并进行双向数据传输。

  • 对于WebSocket是通过tcp和http通行的全双工通信
  • 请求:在进行websocket通信时,首先时tcp链接,在请求头里面会携带Connection:keep-alive,Upgrade(Upgrade是请求网络升级)和Upgrade:websocket(升级为websocket),
  • 响应:在进行websocket通信时,会在响应头里面携带Upgrade:websocketConnection:Upgrade

tcp 首先tcp协议是不能通过浏览器通信的,只能通过node通信

第三方库的使用

websocket-node
  • 客户端
var W3CWebSocket = require('websocket').w3cwebsocket;

var client = new W3CWebSocket('ws://192.168.31.220:8080/');

/**
 * readyState
 * 0,new是为0 链接还没有建立(正在建立)
 * 1,链接建立成功
 * 2,链接正在关闭
 * 3,链接已经关闭
 */
console.log(client.readyState);

client.onerror = function() {
    console.log('Connection Error');
};

client.onopen = function() {
    console.log(client.readyState,client.OPEN);
    console.log('WebSocket Client Connected');

    function sendNumber() {
        if (client.readyState === client.OPEN) {
            var number = Math.round(Math.random() * 0xFFFFFF);
            console.log(number)
            client.send(number.toString());
            // setTimeout(sendNumber, 1000);
        }
    }
    sendNumber();
};

client.onclose = function() {
    console.log('echo-protocol Client Closed');
};

client.onmessage = function(e) {
    console.log(e)
    if (typeof e.data === 'string') {
        console.log("Received: '" + e.data + "'");
    }
};
  • 服务端
var WebSocketServer = require('websocket').server;
var http = require('http');

var server = http.createServer(function (request, response) {
  console.log((new Date()) + ' Received request for ' + request.url);
  response.writeHead(200);
  response.end();
});
server.listen(8080, function () {
  console.log((new Date()) + ' Server is listening on port 8080');
});

const wsServer = new WebSocketServer({
  httpServer: server,
  autoAcceptConnections: false
});
let connectArr = []
wsServer.on('request', function (request) {
  var connection = request.accept();
  connectArr.push(connection)
  console.log((new Date()) + ' Connection accepted.');
  connection.on('message', function (message) {
    console.log(message)
    for (let index = 0; index < connectArr.length; index++) {
      connectArr[index].send(message.utf8Data)

    }
  });
  connection.on('close', function (reasonCode, description) {
    console.log((new Date()) + ' Peer ' + connection.remoteAddress + ' disconnected.');
  });
});
socket.io && koa
  • 客户端
const { io } = require("socket.io-client");
const socket = io.connect("http://192.168.31.220:3000");
(()=>{
    socket.emit("request", "world");
    console.log('emit-connection')

})()
socket.on("connect", () => {
    console.log(socket.id); // x8WIv7-mJelg7on_ALbx
});

socket.on("disconnect", () => {
    console.log(socket.id); // undefined
});
  • 服务端
const koa = require('koa')
const app = new koa()
const server = require('http').createServer(app.callback());
const io = require('socket.io')(server, {
  cors: {
    origin: "*"
  }
});
io.on('connection', (socket) => {
  socket.on('request', function (data) {
    console.log('data' + data)
  })
  console.log('已经链接')
});
server.listen(3000, function () {
  console.log('FUWUQIDONG')
});

萌新交流,互相学习,勿喷