• 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中,我们可以往浏览器发送指定的信息,让客户端重新发起请求,这样就可以保持客户端和服务器的长久连接。

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

  • 相关阅读:
    使用vue-cli搭建SPA项目
    NodeJS的环境搭建+传统ELmentui+vue开发
    vue路由
    Vue基础语法(样式绑定,事件处理,表单,Vue组件)
    动态规划 | 保留重复元素的LCS 1045
    动态规划 | 1007 最大连续子序列和
    数学问题 | 质因数分解:1096
    数学问题 | 连续质因数分解:1096
    数据结构 | 哈希表二次探查法 : 1078
    数学问题 | 1015 进制转换与素数问题
  • 原文地址:https://www.cnblogs.com/wangyage/p/7183331.html
Copyright © 2020-2023  润新知