长轮询

116 阅读2分钟

1 介绍

首先由客户端向服务器发起请求,当服务器收到客户端发来的请求后,服务器端不会直接进行响应,而是先将这个请求挂起,然后判断服务器端数据是否有更新。如果有更新,则进行响应,如果一直没有数据,则到达一定的时间限制才返回。客户端 JavaScript 响应处理函数会在处理完服务器返回的信息后,再次发出请求,重新建立连接

服务端维持一个消息队列,当收到一个请求就检查消息队列看有没有数据有就把数据取出来返回给客户端,因为队列是先进先出所以顺序是对的,没有数据就hold住这个请求一会,众所周知TCP连接后还有一个响应时间如果在响应时间也就是还没响应时,当你看开发者模式这时的status就不是状态码而是pending

举例理解一下

requests.get('www.baidu.com',timeout=(5,10))

这里的代码是一个简单的请求,设置的这个timeout是一个元组的形式,第一个参数为连接超时,第二个是响应超时,这里我们设置10秒,当10秒后没有响应这个连接也结束了,这样就不会hold住。

2 优缺点

优点:明显减少了很多不必要的 http 请求次数,相比之下节约了资源。

缺点:连接挂起也会导致资源的浪费。

3 实现(使用node.js实现)

const http = require('http');
const messages = [];

http.createServer(function(req, res) {
  console.log('client connected');

  if (req.method === 'POST') {
    let chunks = '';

    req.on('data', function(chunk) {
      chunks += chunk;
    });

    req.on('end', function() {
      messages.push(chunks);
      console.log('message received: ' + chunks);
    });
  } else if (req.method === 'GET') {
    res.writeHead(200, { 'Content-Type': 'text/plain', 'Connection': 'keep-alive', 'Cache-Control': 'no-cache' });

    let lastMessageIndex = 0;

    function checkForNewMessages() {
      if (lastMessageIndex < messages.length) {
        res.write(messages.slice(lastMessageIndex).join('\n') + '\n');
        lastMessageIndex = messages.length;
      }
    }

    setInterval(checkForNewMessages, 1000);
    checkForNewMessages();
  }
}).listen(8080);

在此示例中,我们创建了一个HTTP服务器,监听8080端口。通过检查请求的方法(GET或POST),我们可以将请求转换为长轮询机制。在长轮询请求中,我们向客户端发送200响应代码、Connection头和Cache-Control头,以指示我们将保持连接的活动。然后,我们使用setInterval函数和checkForNewMessages函数来持续检查最新的消息,如果有新消息,则将其发送到客户端。

参考资料:

1 blog.csdn.net/m0_69082030…

2 www.php.cn/faq/508820.…