基于servlet3实现长轮询
来源:互联网 发布:go语言编程 pdf 编辑:程序博客网 时间:2024/05/17 08:00
你可能有这样的需求:
客户端需要持续访问服务端获取变化的数据,但是拉取变化的数据这个动作可能比较费时,所以并不能立刻返回结果。如果使用普通的同步请求客户端的连接会一直阻塞在服务端,服务端持有的连接也会越来越多,性能极差。
短链接在请求耗时比较长的场景中效果很差,那用什么方式呢?长连接?长连接建立tcp三次握手后就会和服务器端一直保持连接直到服务端断开连接,但是连接状态会一直保存在web容器中。
使用长轮询更加合理,servlet3支持异步servlet,在服务器端阻塞请求,释放容器线程,在数据准备好之后再返回给客户端。这样客户端请求是同步的而服务端是异步的。
代码模拟示例:实现一个客户端不同用户去拉取数据设置数据,服务端接收设置数据请求并发送到各个客户端的场景。很像一个聊天室。
import javax.servlet.AsyncContext;import javax.servlet.ServletException;import javax.servlet.annotation.WebServlet;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.text.DateFormat;import java.text.SimpleDateFormat;import java.util.*;import java.util.concurrent.ConcurrentHashMap;/** * @author <a href="mailto:liuchangqing@youku.com">liuchangqing</a> * @date 2017/8/2. */@WebServlet(name = "asyServlet",urlPatterns = "/asyServlet.do",asyncSupported = true)public class AsyServlet extends HttpServlet{ //存储请求的所有客户端 private static final Map<String,GetClient> clients = new ConcurrentHashMap<String,GetClient>(); static { //启动一个线程,扫描,关闭所有超时的连接 new Timer().schedule(new TimerTask() { @Override public void run() { long current = System.currentTimeMillis(); for (Map.Entry<String, GetClient> entry : clients.entrySet()) { GetClient client = entry.getValue(); if (client == null) return; if (current - client.time > 20 * 1000) { client.complete(); clients.remove(entry.getKey()); } } } }, 10, 5000); } @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { String action = req.getParameter("action"); if("get".equals(action)){//拉数据 final AsyncContext asyncContext = req.startAsync(); asyncContext.setTimeout(0L); String uid = req.getParameter("uid"); clients.put(uid,new GetClient(asyncContext,uid)); }else if("set".equals(action)){//设置数据 String msg = req.getParameter("msg"); sendMsg(msg); resp.getWriter().print("set success"); } } //消息发送给所有客户端 private void sendMsg(String msg) { Iterator<String> users = clients.keySet().iterator(); while (users.hasNext()){ GetClient cl = clients.get(users.next()); if(cl != null) cl.response(msg); } }}class GetClient{ public AsyncContext asyncContext; public String uid; public long time; public GetClient(AsyncContext asyncContext, String uid) { this.asyncContext = asyncContext; this.uid = uid; this.time = System.currentTimeMillis(); } //关闭连接 public void complete() { response("connect end"); asyncContext.complete(); } public static DateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); //响应 public void response(String message) { Map<String, Object> content = new HashMap<String, Object>(); content.put("messages", message); try { HttpServletResponse response = (HttpServletResponse) asyncContext.getResponse(); PrintWriter writer = response.getWriter(); response.setHeader("Content-type", "text/html;charset=UTF-8"); writer.println(format.format(new Date()) + ",receive:" + content + "<br/>"); writer.flush(); } catch (Exception se) { } }}
发送数据
拉取数据
例子还是比较经典的。
好久没有更新博客了,在农药被人追着打的同时也要坚持写写博客,嘿嘿。
阅读全文
0 0
- 基于servlet3实现长轮询
- Servlet3的异步实现
- Servlet3--基于注解的servlet
- servlet3 实现请求异步处理
- servlet3
- Servlet3
- Servlet3
- servlet3
- 基于Servlet3.0规范的一个HelloWorld
- 基于Servlet3.0的文件上传
- 基于Servlet3.0 comet http长连接
- 基于servlet3.0的文件上传
- springmvc基于servlet3.0特性记录
- spring基于servlet3.0配置上传文件
- Servlet3.0实现上传文件到服务器端
- 文件上传之servlet3.0实现
- Servlet3.0实现的简单mvc框架
- servlet3.0 实现文件的上传
- git 创建版本库
- CSU 1510Happy Robot(dp)
- Bluetooth MESH探究 --- (6) BLE core spec之广播信道防冲突与数据信道选择
- How Many Tables
- Git更新远程仓库代码到本地 git fetch
- 基于servlet3实现长轮询
- Java 并发专题 : Executor详细介绍 打造基于Executor的Web服务器
- 数组
- 欢迎使用CSDN-markdown编辑器
- problem.php?pid=513
- UOJ33树上GCD
- AD中进行集体操作的方法
- FBA4droid 模拟器
- C++第二天--MFC