Serlvet 处理http请求并保持长连接
一.Servlet,一个请求在容器中是如何处理的
Servlet规定的,相应客户请求访问特定Servlet流程如下:
1.客户端发出请求。
2.Servlet容器接收客户请求解析。
3.Servlet容器创建一个ServletRequest对象。
其中包含客户请求信息及其他关于客户的信息如请求头,请求正文,客户机的IP等。
4.容器创建一个ServletResponse对象。
5.容器调用客户请求的Servlet的service方法,并且把ServletRequest和ServletResponse作为参数传入。
6.Servlet从客户参数中获得客户请求信息,并调用对应的doGet或doPost处理。
7.Servlet利用ServletResponse对象来生产相应结果。
8.Servlet容器把Servlet生成的结果发给客户。
二.Servlet3.0长连接
servlet3.0规范中添加了异步处理,即一部分操作处理完成之后,先行把数据返回来,对于另一部分比较耗时的操作可以放置到另外一个线程中进行处理,该线程保留有连接的请求和响应对象,在处理完成之后可以把处理的结果通知到客户端,实例代码如下:
import java.io.IOException; import java.io.PrintWriter; import java.util.Date; import javax.servlet.AsyncContext; import javax.servlet.AsyncEvent; import javax.servlet.AsyncListener; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @WebServlet(urlPatterns="/demo", asyncSupported=true) public class AsynServlet extends HttpServlet { private static final long serialVersionUID = -8016328059808092454L; /* (non-Javadoc) * @see javax.servlet.http.HttpServlet#service(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse) */ @Override protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { resp.setContentType("text/html;charset=UTF-8"); PrintWriter out = resp.getWriter(); out.println("进入Servlet的时间:" + new Date() + "."); out.flush(); //在子线程中执行业务调用,并由其负责输出响应,主线程退出 final AsyncContext ctx = req.startAsync(); ctx.setTimeout(200000); new Work(ctx).start(); out.println("结束Servlet的时间:" + new Date() + "."); out.flush(); } } class Work extends Thread{ private AsyncContext context; public Work(AsyncContext context){ this.context = context; } @Override public void run() { try { Thread.sleep(2000);//让线程休眠2s钟模拟超时操作 PrintWriter wirter = context.getResponse().getWriter(); wirter.write("延迟输出"); wirter.flush(); context.complete(); } catch (InterruptedException e) { } catch (IOException e) { } } }
有些时候,我们可能需要客户端和服务器保持长连接的时候,我们可以使用这个特性,让服务器长时间保持客户端的请求以及对客户端的响应,做法如下:
对于异步执行,我们可以添加一个监听器,监听异步执行的状态。
ctx.addListener(new AsyncListener() { @Override public void onTimeout(AsyncEvent arg0) throws IOException { // TODO Auto-generated method stub } @Override public void onStartAsync(AsyncEvent arg0) throws IOException { // TODO Auto-generated method stub } @Override public void onError(AsyncEvent arg0) throws IOException { // TODO Auto-generated method stub } @Override public void onComplete(AsyncEvent arg0) throws IOException { // TODO Auto-generated method stub } });
在Servlet返回之前,我们可以把持有request和response对象的AsyncContext对象放置到一个全局可访问的静态容器中
map.put("id",ctx);
如果连接出错或者连接完的时候我们可以在onError以及onComplete方法中移除掉对应连接的AsyncContext
map.remove("id",ctx);
在超时的回调方法onTimeout中,我们可以往浏览器发送指定的信息,让客户端重新发起请求,这样就可以保持客户端和服务器的长久连接。
如下服务器和客户端之间数据交互的模型图

- 上一篇: python实现数据导出到excel--普通格式
- 下一篇: JAVA实现长连接(含心跳检测)Demo