java 实现长轮询(LongPolling)

本文详细介绍了Java中长轮询(long polling)的概念及其与pull、push的区别。通过具体实例展示了长轮询的工作原理,包括其Java实现代码及如何利用观察者模式进行事件通知。

pull,push的区别

pull或者push都是为了数据传输,只是发起方不同。下定义提供数据的是服务端S,接受数据的为客户端C。

区别

发起方不同

pull发起方为客户端,服务端为被动接收,当服务端没有数据需要传输时,该次pull属于是无效的。
push发起方为服务端,服务端有数据需要推送时,遍历需要该数据的客户端,然后将数据发送给客户端。这里服务端需要保存客户端的链接。

时效性不同

pull通常是客户端在一定心跳间隔时间发起,在数据变化过后的下次心跳时间才能获取到最新的数据。时效性较差。
push在服务端有数据时就会发送给到客户端,基本数据变化了就能立马到客户端。时效性较强。

对于服务端和客户端的资源消耗

pull,如果不是经常变化的数据,pull的请求大部分都是无意义的,浪费了服务端和客户端的流量,服务端的cpu等资源。
push,服务端需要保存客户端的信息,或者客户端的链接。如果客户端较多,遍历客户端信息或者保存TCP链接对于服务端来说压力较大。

数据处理负责人

pull的负责人是客户端,如果有数据未被客户端处理,需要首先考虑是否是客户端的问题。比如是否需要新增客户端,检查客户端的代码配置。
push的负责人是服务端,如果有数据未被客户端处理,需要首先考虑是否是服务端的问题。例如是否是服务端数据未推送。

总结

看时间敏感,数据大小,数据处理难度,客户端服务端性能选择。还有一种处于pull和push之间的长轮询。

长轮询

长轮询本质上是pull,但是在客户端发起请求时,服务端不会马上返回,而是保持该链接。如果在一个时间间隔后没有数据,那么服务端会返回一个空的数据。如果在一个时间间隔内有数据返回,那么他就返回数据。
这样可以由服务端来控制客户端的请求频率,避免不必要的请求,还能及时的返回数据,保证数据时效性。可以避免在数据变化不多的情况下的资源消耗。

java代码

参考nacos。

Controller

首先定义controller,这里需要拿到HttpServletResponse。可以自定义返回的内容,header等。拿到HttpServletRequest ,获取请求头中的数据,例如本次是否长轮询,长轮询时间,源ip等信息。

    @PostMapping("/listener")
    @Secured(action = ActionTypes.READ, signType = SignType.CONFIG)
    public void listener(HttpServletRequest request, HttpServletResponse response){
   
   
		// do long-polling
        inner.doPollingConfig(request, response, clientMd5Map, probeModify.length());
	}
inner.doPollingConfig
    /**
     * long polling the config.
     */
    public String doPollingConfig(HttpServletRequest request, HttpServletResponse response,
            Map<String, String> clientMd5Map, int probeRequestSize) throws IOException {
   
   
        
        // Long polling.
        if (LongPollingService.isSupportLongPolling(request)) {
   
   
            longPollingService.addLongPollingClient(request, response, clientMd5Map, probeRequestSize);
            return HttpServletResponse.SC_OK + "";
        }
        //不支持的当成普通请求处理
    }
longPollingService.addLongPollingClient

获取请求头中的一些参数,例如长轮询到期时间,是否本次需要长轮询,appName等信息。

    /**
     * Add LongPollingClient.
     *
     * @param req              HttpServletRequest.
     * @param rsp              HttpServletResponse.
     * @param clientMd5Map     clientMd5Map.
     * @param probeRequestSize probeRequestSize.
     */
    public void addLongPollingClient(HttpServletRequest req, HttpServletResponse rsp, Map<String, String> clientMd5Map,
            int probeRequestSize) {
   
   
        
        String str = req.getHeader(LongPollingService.LONG_POLLING_HEADER);
        String noHangUpFlag = req.getHeader(LongPollingService.LONG_POLLING_NO_HANG_UP_HEADER);
        String appName = req.getHeader(RequestUtil.CLIENT_APPNAME_HEADER);
        String tag = req.getHeader("Vipserver-Tag");
        int delayTime = SwitchService.getSwitchInteger(SwitchService.FIXED_DELAY_TIME, 500);
        
        // Add delay time for LoadBalance, and one response is returned 500 ms in advance to avoid client timeout.
        long timeout = Math.max(10000, Long.parseLong(str) - delayTime);
        //是否是固定时长的长轮询,如果是,那么会忽略请求头的长轮询时间
        if (isFixedPolling()) {
   
   
            timeout = Math.max(10000, getFixedPollingInterval());
            // Do nothing but set fix polling timeout.
        } else {
   
   
            long start = System.currentTimeMillis();
            //判断是否这次请求来的时候已经有变化了,如果有,返回成一个list
            List<String> changedGroups = MD5Util.compareMd5(req, rsp, clientMd5Map);
            if (changedGroups.size() > 0) {
   
   
            	//变化的list不为空就返回
                generateResponse(req, rsp, changedGroups);
                return;
            } else if (noHangUpFlag != null && noHangUpFlag.equalsIgnoreCase(TRUE_STR)) {
   
   
                //没有变化,并且本次不需要长轮询,直接返回,并且没有返回值。
                return;
            }
        }
        String ip = RequestUtil.getRemoteIp(req)
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值