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)

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

1102

被折叠的 条评论
为什么被折叠?



