首页 > 代码库 > Serlvet 处理http请求并保持长连接

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规范中添加了异步处理,即一部分操作处理完成之后,先行把数据返回来,对于另一部分比较耗时的操作可以放置到另外一个线程中进行处理,该线程保留有连接的请求和响应对象,在处理完成之后可以把处理的结果通知到客户端,实例代码如下:

 

[java] view plain copy
 
 print?
  1. import java.io.IOException;  
  2. import java.io.PrintWriter;  
  3. import java.util.Date;  
  4. import javax.servlet.AsyncContext;  
  5. import javax.servlet.AsyncEvent;  
  6. import javax.servlet.AsyncListener;  
  7. import javax.servlet.ServletException;  
  8. import javax.servlet.annotation.WebServlet;  
  9. import javax.servlet.http.HttpServlet;  
  10. import javax.servlet.http.HttpServletRequest;  
  11. import javax.servlet.http.HttpServletResponse;  
  12. @WebServlet(urlPatterns="/demo", asyncSupported=true)  
  13. public class AsynServlet extends HttpServlet {  
  14.     private static final long serialVersionUID = -8016328059808092454L;  
  15.       
  16.     /* (non-Javadoc) 
  17.      * @see javax.servlet.http.HttpServlet#service(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse) 
  18.      */  
  19.     @Override  
  20.     protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {  
  21.             resp.setContentType("text/html;charset=UTF-8");  
  22.             PrintWriter out = resp.getWriter();  
  23.             out.println("进入Servlet的时间:" + new Date() + ".");  
  24.             out.flush();  
  25.   
  26.             //在子线程中执行业务调用,并由其负责输出响应,主线程退出  
  27.             final AsyncContext ctx = req.startAsync();  
  28.             ctx.setTimeout(200000);  
  29.             new Work(ctx).start();  
  30.             out.println("结束Servlet的时间:" + new Date() + ".");  
  31.             out.flush();  
  32.     }  
  33. }  
  34.   
  35. class Work extends Thread{  
  36.     private AsyncContext context;  
  37.       
  38.     public Work(AsyncContext context){  
  39.         this.context = context;  
  40.     }  
  41.     @Override  
  42.     public void run() {  
  43.         try {  
  44.             Thread.sleep(2000);//让线程休眠2s钟模拟超时操作  
  45.             PrintWriter wirter = context.getResponse().getWriter();           
  46.             wirter.write("延迟输出");  
  47.             wirter.flush();  
  48.             context.complete();  
  49.         } catch (InterruptedException e) {  
  50.               
  51.         } catch (IOException e) {  
  52.               
  53.         }  
  54.     }  
  55. }  

 

有些时候,我们可能需要客户端和服务器保持长连接的时候,我们可以使用这个特性,让服务器长时间保持客户端的请求以及对客户端的响应,做法如下:

对于异步执行,我们可以添加一个监听器,监听异步执行的状态。

[java] view plain copy
 
 print?
  1. ctx.addListener(new AsyncListener() {  
  2.     @Override  
  3.     public void onTimeout(AsyncEvent arg0) throws IOException {  
  4.         // TODO Auto-generated method stub                
  5.     }             
  6.     @Override  
  7.     public void onStartAsync(AsyncEvent arg0) throws IOException {  
  8.         // TODO Auto-generated method stub                
  9.     }             
  10.     @Override  
  11.     public void onError(AsyncEvent arg0) throws IOException {  
  12.         // TODO Auto-generated method stub  
  13.     }  
  14.     @Override  
  15.     public void onComplete(AsyncEvent arg0) throws IOException {  
  16.         // TODO Auto-generated method stub  
  17.     }  
  18. });  

在Servlet返回之前,我们可以把持有request和response对象的AsyncContext对象放置到一个全局可访问的静态容器中

map.put("id",ctx);

如果连接出错或者连接完的时候我们可以在onError以及onComplete方法中移除掉对应连接的AsyncContext

map.remove("id",ctx);

在超时的回调方法onTimeout中,我们可以往浏览器发送指定的信息,让客户端重新发起请求,这样就可以保持客户端和服务器的长久连接。

如下服务器和客户端之间数据交互的模型图

技术分享

Serlvet 处理http请求并保持长连接