基于java servlet的http推送服务
来源:互联网 发布:ip138离线数据库 编辑:程序博客网 时间:2024/06/18 12:01
前几天项目要求实现安卓手机端的推送功能,由于原来的工程与服务端通信用的是http的协议,又不想用极光推送,所以想自己做一个使用http的推送实现,最后研究了几天,今天把例子发出来:
http的原理就是。请求-响应过程,基本流程如下:
在一般响应的过程中,服务端一般不会阻塞,也就是说,服务端在收到客户端的请求后会立即进行处理,然后响应
数据给客户端,如果服务端响应时间过长,客户端就会出异常。但是,在http推送的过程中,客户端要和服务端保持一个连接,当服务端需要推送的时候,才把数据响应给客户端。这样就需要另外一个请求来通知服务端进行推送,基本流程如下:
基本流程详解:客户端给服务端发送一个请求,等待响应,服务端收到客户端的请求之后,并不会立即做出响应,而是会阻塞不动(因为http每一个请求都是一个线程)。在这个过程中,需要保证客户端不会出现time out异常(可以设置时间)。当有推送的客户端需要进行推送的时候,会向服务端发送一个推送的请求。服务端收到推送的请求后,解锁前面那个被阻塞的请求,并响应给客户端。客户端收到响应后要再次发送请求给服务端,依次循环。这样就达成了推送的效果。话不多说,直接上代码:
首先,新建一个web项目HttpPlusTest:
新建一个客户端servlet请求,用来处理来自客户端的请求,在这里,需要使用一个对象来使线程阻塞,为了让后面的请求可以解锁线程并设置推送内容,我们创造一个Map类型的对象,并将对象放入系统全局变量里面:
package com.sgcc.test;import java.io.IOException;import java.util.ArrayList;import java.util.HashMap;import java.util.List;import java.util.Map;import javax.servlet.ServletException;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;public class ClientPush extends HttpServlet { private static final long serialVersionUID = 1L; public ClientPush() { super(); } protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //获取系统全局变量,在这里为了方便,暂时用Appliection代替。如果获取到的内容为空,则在下面new一个集合放进来, //这个集合里面存放了所有要被推送的内容的对象,暂时用Map代替,在实际使用的时候可以定义实体类。 List<Map<String, String>> pushList = (List<Map<String, String>>) request.getSession().getServletContext() .getAttribute("PUSH"); //使用这个对象的线程锁来让当前请求的线程暂停执行,并将这个对象放入全局变量,在需要推送的时候调用 这个对象的notify方法可以唤起线程 Map<String, String> temp = new HashMap<String, String>(); if (pushList == null) { List<Map<String, String>> list = new ArrayList<>(); request.getSession().getServletContext().setAttribute("PUSH", list); list.add(temp); } else { pushList.add(temp); } //将对象和当前线程关联起来。在调用对象的wait()方法的时候,当前线程会阻塞 synchronized (temp) { try { //使当前线程阻塞。等待其他线程唤醒它 temp.wait(); //被唤醒后,将内容发送给客户端,响应完成! response.getWriter().write(temp.get("pushContext")); response.getWriter().flush(); } catch (InterruptedException e) { e.printStackTrace(); } finally { if (pushList != null) { pushList.remove(temp); } } } } protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); }}
当客户端请求到这个servlet的时候,会在44行代码的时候被阻塞,需要另外一个线程来唤醒这个线程,所以,我们还需要一个用来处理推送客户端的servlet 来遍历唤醒他:
package com.sgcc.test;import java.io.IOException;import java.util.Date;import java.util.List;import java.util.Map;import javax.servlet.ServletException;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;public class PutPush extends HttpServlet { private static final long serialVersionUID = 1L; public PutPush() { super(); } protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 获取当前系统所有待推送的请求 List<Map<String, String>> pushList = (List<Map<String, String>>) request.getSession().getServletContext() .getAttribute("PUSH"); if (pushList == null || pushList.size() == 0) { response.getWriter().write( "推送失败,"); response.getWriter().flush(); return; } // 遍历推送 for (Map<String, String> map : pushList) { synchronized (map) { // 设置推送内容 map.put("pushContext", new Date().toString() + "\n"); map.notify(); } } response.getWriter().write( "推送成功,共推送:" + pushList.size() + "个"); response.getWriter().flush(); } protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); }}
最后还要在web.xml 中声明这两个servlet:
<?xml version="1.0" encoding="UTF-8"?><web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5"> <display-name>HttpPlusTest</display-name> <welcome-file-list> <welcome-file>index.html</welcome-file> <welcome-file>index.htm</welcome-file> <welcome-file>index.jsp</welcome-file> <welcome-file>default.html</welcome-file> <welcome-file>default.htm</welcome-file> <welcome-file>default.jsp</welcome-file> </welcome-file-list> <servlet> <description></description> <display-name>ClientPush</display-name> <servlet-name>ClientPush</servlet-name> <servlet-class>com.sgcc.test.ClientPush</servlet-class> </servlet> <servlet-mapping> <servlet-name>ClientPush</servlet-name> <url-pattern>/ClientPush</url-pattern> </servlet-mapping> <servlet> <description></description> <display-name>PutPush</display-name> <servlet-name>PutPush</servlet-name> <servlet-class>com.sgcc.test.PutPush</servlet-class> </servlet> <servlet-mapping> <servlet-name>PutPush</servlet-name> <url-pattern>/PutPush</url-pattern> </servlet-mapping></web-app>
简易的客户端代码:
package com.brains.test;import java.io.InputStream;import java.net.HttpURLConnection;import java.net.MalformedURLException;import java.net.URL;import java.net.URLConnection;public class TestHttp { public static void main(String[] args) throws Exception { URL url=new URL("http://127.0.0.1:7002/HttpPlusTest/ClientPush"); HttpURLConnection connection = (HttpURLConnection) url.openConnection(); connection.connect(); connection.setConnectTimeout(0); InputStream in = connection.getInputStream(); byte[] b=new byte[1024]; int len=0; while((len=in.read(b))!=-1){ System.out.println(new String(b)); } }}
执行这段客户端代码后,控制台暂时不会输出任何东西,然后在浏览器请求推送的时候,客户端会吧当前时间输出出来
ps:个人原创,转载请注明出处!
- 基于java servlet的http推送服务
- Servlet-基于的HTTP协议
- 基于netty-socketio的web推送服务
- 基于webservice的邮件消息推送服务
- 基于netty-socketio的web推送服务
- 基于netty-socketio的web推送服务
- 基于netty-socketio的web推送服务
- 基于netty-socketio的web推送服务
- 基于Java的WebSocket推送
- ZPush--基于netty4实现的苹果通知推送服务(APNs)Java客户端
- Servlet 规范笔记—基于http协议的servlet
- 基于java的WebSocket的主动推送
- 基于openfire+smack的Android、消息推送服务
- 基于位置服务的信息推送系统设计
- 基于java-flex-blazeds的消息推送
- Java基于Socket的简单推送
- 基于dwr框架的java推送
- 基于angular2 的 http服务封装
- 4.08,linux初学:基本的linux操作和vim操作
- visual studio 2017 update 1 出来了
- JavaAnnotation注解定义与使用
- java分布式服务框架Dubbo的介绍与使用
- AOJ0525:Osenbei(DFS + Bitset)
- 基于java servlet的http推送服务
- window下编译spark2.1.0
- jQuery遍历
- 知行合一
- 023删除元素
- 跳槽感想
- 【算法竞赛入门经典学习日记】第二章 循环结构程序设计
- 五.MUI
- Java进阶知识