介绍

众所周知,数据交互有两种模式:Push(推模式)、Pull(拉模式)。

推模式指的是客户端与服务端建立好网络长连接,服务方有相关数据,直接通过长连接通道推送到客户端。其优点是及时,一旦有数据变更,客户端立马能感知到;另外对客户端来说逻辑简单,不需要关心有无数据这些逻辑处理。缺点是不知道客户端的数据消费能力,可能导致数据积压在客户端,来不及处理。

拉模式指的是客户端主动向服务端发出请求,拉取相关数据。其优点是此过程由客户端发起请求,故不存在推模式中数据积压的问题。缺点是可能不够及时,对客户端来说需要考虑数据拉取相关逻辑,何时去拉,拉的频率怎么控制等等。

详解

说到Long Polling(长轮询),必然少不了提起Polling(轮询),这都是拉模式的两种方式。

Polling是指不管服务端数据有无更新,客户端每隔定长时间请求拉取一次数据,可能有更新数据返回,也可能什么都没有。

Long Polling原理也很简单,相比Polling,客户端发起Long Polling,此时如果服务端没有相关数据,会hold住请求,直到服务端有相关数据,或者等待一定时间超时才会返回。返回后,客户端又会立即再次发起下一次Long Polling。这种方式也是对拉模式的一个优化,解决了拉模式数据通知不及时,以及减少了大量的无效轮询次数。

所谓的hold住请求指的服务端暂时不回复结果,保存相关请求,不关闭请求链接,等相关数据准备好,写会客户端。

前面提到Long Polling如果当时服务端没有需要的相关数据,此时请求会hold住,直到服务端把相关数据准备好,或者等待一定时间直到此次请求超时,这里大家是否有疑问,为什么不是一直等待到服务端数据准备好再返回,这样也不需要再次发起下一次的Long Polling,节省资源?

主要原因是网络传输层主要走的是tcp协议,tcp协议是可靠面向连接的协议,通过三次握手建立连接。但是所建立的连接是虚拟的,可能存在某段时间网络不通,或者服务端程序非正常关闭,亦或服务端机器非正常关机,面对这些情况客户端根本不知道服务端此时已经不能互通,还在傻傻的等服务端发数据过来,而这一等一般都是很长时间。

当然tcp协议栈在实现上有保活计时器来保证的,但是等到保活计时器发现连接已经断开需要很长时间,如果没有专门配置过相关的tcp参数,一般需要2个小时,而且这些参数是机器操作系统层面,所以,以此方式来保活不太靠谱,故Long Polling的实现上一般是需要设置超时时间的。

实现

Long Polling的实现很简单,可分为四个过程:

  • 发起Polling,发起Polling很简单,只需向服务器发起请求,此时服务端还未应答,所以客户端与服务端之间一直处于连接状态。
  • 数据推送,如果服务器端有相关数据,此时服务端会将数据通过此前建立的通道发回客户端。
  • Polling终止,Polling终止情况有三种:若服务端返回相关数据,此时客户端收到数据后,关闭请求连接,结束此次Polling过程。若客户端等待设定的超时时间后,服务端依然没有返回数据,此时客户端需要主动终止此次Polling请求。若客户端收到网络故障或异常,此时客户端自然也是需要主动终止此次Polling请求。
  • 重新Polling,终止上次Polling后,客户端需要立即再次发起Polling请求。这样才能保证拉取数据的及时性。

代码实现起来也很简单,Http Call按照上述过程就很方便实现LongPolling。下面Code只是简单展示过程,在具体场景下,根据具体的业务逻辑进行调整。

客户端Code

package com.andy.example.longpolling.client;

import java.io.BufferedReader;

import java.io.IOException;

import java.io.InputStreamReader;

import java.net.HttpURLConnection;

import java.net.URL;

/**

* Created by andy on 17/7/6.

*/

public class ClientBootstrap {

public static final String URL = "http://localhost:8080/long-polling";

public static void main(String[] args) {

int i = 0;

while (true) {

System.out.println("第" + (++i) + "次 longpolling");

HttpURLConnection connection = null;

try {

URL getUrl = new URL(URL);

connection = (HttpURLConnection) getUrl.openConnection();

connection.setReadTimeout(50000);//这就是等待时间,设置为50s

connection.setConnectTimeout(3000);

connection.setRequestMethod("GET");

connection.setRequestProperty("Accept-Charset", "utf-8");

connection.setRequestProperty("Content-Type", "application/json");

connection.setRequestProperty("Charset", "UTF-8");

if (200 == connection.getResponseCode()) {

BufferedReader reader = null;

try {

reader = new BufferedReader(new InputStreamReader(connection.getInputStream(), "UTF-8"));

StringBuilder result = new StringBuilder(256);

String line = null;

while ((line = reader.readLine()) != null) {

result.append(line);

}

System.out.println("结果 " + result);

} finally {

if (reader != null) {

reader.close();

}

}

}

} catch (IOException e) {

} finally {

if (connection != null) {

connection.disconnect();

}

}

}

}

}

服务端Code

package com.andy.example.longpolling.server;

import javax.servlet.ServletException;

import javax.servlet.http.HttpServlet;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;

import java.io.IOException;

import java.io.PrintWriter;

import java.util.Random;

import java.util.concurrent.TimeUnit;

import java.util.concurrent.atomic.AtomicLong;

/**

* Created by andy on 17/7/6.

*/

public class LongPollingServlet extends HttpServlet {

private Random random = new Random();

private AtomicLong sequenceId = new AtomicLong();

private AtomicLong count = new AtomicLong();

@Override

protected void doGet(HttpServletRequest request, HttpServletResponse response)

throws ServletException, IOException {

System.out.println("第" + (count.incrementAndGet()) + "次 longpolling");

int sleepSecends = random.nextInt(100);

//随机获取等待时间,来通过sleep模拟服务端是否准备好数据

System.out.println("wait " + sleepSecends + " second");

try {

TimeUnit.SECONDS.sleep(sleepSecends);//sleep

} catch (InterruptedException e) {

}

PrintWriter out = response.getWriter();

long value = sequenceId.getAndIncrement();

out.write(Long.toString(value));

}

}

结果

应用

WebQQ、Comet都用到长轮询技术,另外一些使用Pull模式消费的消息系统,都会使用Long Polling技术进行优化。

易语言服务端与客户端怎么传送_配置中心是怎么推送的?动手实现一个 Long Polling 长轮询...相关推荐

  1. 易语言 服务端给客户端发弹窗信息源码

    易语言 服务端给客户端发弹窗信息源码 需要用到服务器 云服务器_云主机_弹性云主机租用尽在 玖毅云 源码下载:易语言服务器给客户端发送弹窗源码.rar-其它文档类资源-CSDN下载 服务端源码 .版本 ...

  2. Oracle (1) :服务端和客户端的安装与配置

    一.Oracle概述 Oracle公司-甲骨文公司,全称甲骨文股份有限公司(甲骨文软件系统有限公司),是全球最大的企业级软件公司,总部位于美国加利福尼亚州的红木滩.1989年正式进入中国市场.2013 ...

  3. nagios 服务端与客户端监控安装与详细配置,各配置文件详解

    nagios 安装与部署------ 1.安装前准备 (1)创建nagios用户和用户组    [root@localhost ~]#groupadd nagios                us ...

  4. sse服务器推送性能,SSE 服务端向客户端推送

    传统的ajax都是由客户端主动去请求,服务端才可以返回数据 而sse是建立一个通道,并且在断线后自动重连,由服务端去推送,不需要客户端去主动请求,只需要建立通道 websocket是双向通信 客户端可 ...

  5. oracle 设置监听和服务,oracle服务端和客户端之间的网络监听如何设置呢?

    racle服务端和客户端之间的网络监听设置 假如我现在有两个数据库kkman和orcl,现在我想在服务端设立两个监听来处理从客户端发过来的连接请求. ------------------------- ...

  6. Go语言实现TCP服务端和客户端

    Go语言实现TCP服务端和客户端 Go语言实现TCP通信 TCP协议 TCP服务端 TCP客户端 本文转载自Go语言实现TCP通信 Go语言实现TCP通信 TCP协议 TCP/IP(Transmiss ...

  7. 使用HTML5的WebSocket实现服务端和客户端数据通信(有演示和源码)

    WebSocket协议是基于TCP的一种新的网络协议.WebSocket是HTML5开始提供的一种浏览器与服务器间进行全双工通讯的网络技术.依靠这种技术可以实现客户端和服务器端的长连接,双向实时通信. ...

  8. 【★更新★】高性能 Windows Socket 服务端与客户端组件(HP-Socket v2.0.1 源代码及测试用例下载)...

    HP-Socket 以前为某大型通信项目开发了一套通用 Windows Socket TCP 底层通信组件,组件代号为 HP-Socket.现在把 HP-Socket 的所有代码向大众公开,希望能对大 ...

  9. C# Socket服务端与客户端通信(包含大文件的断点传输)

    步骤: 一.服务端的建立 1.服务端的项目建立以及页面布局 2.各功能按键的事件代码 1)传输类型说明以及全局变量 2)Socket通信服务端具体步骤:   (1)建立一个Socket   (2)接收 ...

最新文章

  1. sound.js # pixi辅助插件 — 中文翻译教程
  2. mysql深入使用教程_深入mysql基础知识的详解
  3. Eclipse反编译插件安装
  4. Android什么是函数,什么是函数响应式编程(JavaAndroid版本)
  5. CG CTF WEB 单身二十年
  6. 深度学习中反向传播得到的损失是一个标量
  7. 理解zookeeper的一致性及缺点
  8. 使用 Angular Transfer State 的一个具体例子
  9. 面试了3个‘85前’的嵌入式软件工程师
  10. QuickBI助你成为分析师-仪表板钻取的实现
  11. android 的a标签,Android开发技巧之在a标签或TextView控件中单击链接弹出Activity(自定义动作)...
  12. linux RAID10测试
  13. 【铨顺宏项目推荐】RFID无线射频识别技术的设计思路
  14. 怎样修改管家婆服务器密码,管家婆辉煌版如何设置权限和修改操作员密码口令...
  15. imageAI使用教程
  16. Ruby 安装 - Linux
  17. 英文文献调研方法综述
  18. 读书笔记:《牛奶可乐经济学》
  19. phpmyadmin mysql_phpmyadmin
  20. java 计算父亲节_java实现计算周期性提醒的示例

热门文章

  1. 【爬虫剑谱】二卷2章 实战篇-精美动漫图片爬取并保存
  2. JDK 1.6环境变量的设置
  3. RabbitMQ学习笔记:安装环境
  4. cmd 日志刷新卡屏
  5. Navicat 创建mysql事件
  6. 小学计算机知识点,小学信息技术单元知识点目录介绍
  7. 字符串常量与字符数组的区别和字符串常量易错点
  8. 50.本地VMware环境虚拟机的异地(Azure)容灾(上)
  9. ERC223以太坊通证标准
  10. 青云QingCloud携手伟仕佳杰打造专业企业级云服务