短轮询,长轮询,SSE的应用场景。


前言

长轮询、短轮询和SSE(Server-Sent Events)都是Web应用中常用的实时通信技术,它们各有特点和适用场景。以下是对这三种技术的详细解析。


一、短轮询

工作原理:

  • 客户端通过定期向服务器发送HTTP请求来查询是否有新的数据。
  • 服务器在接收到请求后,立即返回当前可用的数据,无论是否有新数据。
  • 客户端收到响应后,解析数据并处理,然后再次发起新的请求,重复以上步骤。

优点:

  • 实现简单,易于部署。
  • 兼容性好,只使用了常规的HTTP请求和响应。

缺点:

  • 频繁的HTTP请求会增加服务器和网络的负载。
  • 实时性有限,因为客户端只能在轮询间隔内获取到更新。

二、长轮询

工作原理:

  • 客户端向服务器发送一个HTTP请求,但服务器不会立即返回响应。
  • 服务器会保持请求打开,直到有新数据可用或者超时。
  • 一旦有新数据或者超时,服务器返回响应给客户端。
  • 客户端收到响应后,解析数据并处理,然后再次发起新的请求。

优点:

  • 减少了不必要的轮询,降低了网络和服务器的负载。
  • 相较于短轮询,提高了实时性,因为服务器可以在数据可用时立即推送。

缺点:

  • 仍然需要定期发起新的请求,因此在某种程度上仍有一定的轮询成本。
  • 不同浏览器对于长连接的支持程度不同,有一定的兼容性问题。

三、SSE

工作原理:

  • SSE是一种基于HTTP长连接技术,允许服务器向客户端浏览器实时推送更新。
  • 客户端通过创建一个EventSource对象并指向服务器上的一个URL来发起请求,这个请求保持打开状态。
  • 服务器可以在这个单一的TCP连接上不断发送新的数据块,这些数据块被称为“事件”。
  • 每个事件包含类型(可选)、数据和一些元数据(如事件ID,重新连接时间间隔等)。

优点:

  • 实现了服务器向客户端的单向实时数据推送。
  • 使用简单的HTTP协议,现有的服务器软件都支持。

缺点:

  • 只能用于传送文本数据,需要将二进制数据编码后传送。
  • SSE协议相对简单,但也需要关注一些细节问题,如避免内存泄漏等。

四、短轮询、长轮询和SSE的示例:

4.1、短轮询示例

后端代码(使用Spring Boot框架):

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class ShortPollingController {

    // 模拟获取最新消息的方法
    @GetMapping("/shortPolling/news")
    public String getLatestNews() {
        // 这里可以从数据库或其他数据源获取最新新闻
        // 示例中简单返回固定消息
        return "这是最新的新闻内容";
    }
}

前端代码(使用JavaScript和AJAX):

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>短轮询示例</title>
</head>
<body>
    <div id="news"></div>
    <script>
        function shortPolling() {
            // 创建XMLHttpRequest对象
            const xhr = new XMLHttpRequest();
            xhr.open('GET', '/shortPolling/news', true);
            xhr.onreadystatechange = function () {
                if (xhr.readyState === 4 && xhr.status === 200) {
                    document.getElementById('news').innerHTML = xhr.responseText;
                }
            };
            xhr.send();
            // 每隔30秒发送一次请求
            setTimeout(shortPolling, 30000);
        }
        // 初始启动短轮询
        shortPolling();
    </script>
</body>
</html>

在这个示例中,客户端每隔30秒向服务器发送一次HTTP请求,询问是否有新的新闻内容。服务器在收到请求后,立即返回当前最新的新闻内容。


4.2、长轮询示例

后端代码(使用Spring Boot框架):

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.context.request.async.DeferredResult;
import java.util.concurrent.TimeUnit;

@RestController
public class LongPollingController {

    @GetMapping("/longPolling/chat")
    public DeferredResult<String> getChatMessage() {
        DeferredResult<String> result = new DeferredResult<>(10000L); // 设置超时时间为10秒

        // 模拟异步获取消息,实际应用中可能从消息队列等获取
        new Thread(() -> {
            try {
                // 模拟业务处理延迟
                TimeUnit.SECONDS.sleep(3);
                // 假设获取到新消息
                result.setResult("这是新的聊天消息");
            } catch (InterruptedException e) {
                e.printStackTrace();
                result.setErrorResult("获取消息失败");
            }
        }).start();

        return result;
    }
}

前端代码(使用JavaScript和AJAX):

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>长轮询示例</title>
</head>
<body>
    <div id="chatMessage"></div>
    <script>
        function longPolling() {
            const xhr = new XMLHttpRequest();
            xhr.open('GET', '/longPolling/chat', true);
            xhr.onreadystatechange = function () {
                if (xhr.readyState === 4) {
                    if (xhr.status === 200) {
                        document.getElementById('chatMessage').innerHTML = xhr.responseText;
                    } else {
                        console.log('请求出错,状态码:' + xhr.status);
                    }
                    // 无论请求结果如何,再次发起长轮询请求
                    longPolling();
                }
            };
            xhr.send();
        }
        // 初始启动长轮询
        longPolling();
    </script>
</body>
</html>

在这个示例中,客户端向服务器发送一个长轮询请求,服务器会保持请求打开,直到有新消息可用或者超时。一旦有新消息或者超时,服务器返回响应给客户端。客户端收到响应后,解析数据并处理,然后再次发起新的长轮询请求。


4.3、SSE示例

后端代码(使用Spring Boot框架):

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.http.MediaType;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;

import java.io.IOException;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

@RestController
public class SseController {

    @GetMapping(value = "/sse", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
    public SseEmitter streamEvents() {
        SseEmitter emitter = new SseEmitter();

        ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor();
        executor.scheduleAtFixedRate(() -> {
            try {
                emitter.send(SseEmitter.event().data("这是服务器推送的实时数据:" + System.currentTimeMillis()));
            } catch (IOException e) {
                emitter.completeWithError(e);
            }
        }, 0, 5, TimeUnit.SECONDS); // 每5秒推送一次数据

        emitter.onCompletion(() -> executor.shutdown());
        emitter.onError((e) -> executor.shutdown());

        return emitter;
    }
}

前端代码(使用JavaScript和AJAX):

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>SSE示例</title>
</head>
<body>
    <div id="sseData"></div>
    <script>
        const eventSource = new EventSource('/sse');

        eventSource.onmessage = function(event) {
            document.getElementById('sseData').innerHTML += event.data + '<br>';
        };

        eventSource.onerror = function(event) {
            console.error("EventSource failed:", event);
            eventSource.close();
        };
    </script>
</body>
</html>

在这个示例中,客户端通过创建一个EventSource对象并指向服务器上的/sse URL来发起SSE请求。服务器在接收到请求后,保持连接打开,并每5秒向客户端推送一次实时数据。客户端收到数据后,将其显示在页面上。

总结

以上示例展示了短轮询、长轮询和SSE的基本实现方式,可以根据具体需求选择适合的技术来实现实时通信功能。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值