E81086713E446D36F62B2AA2A3502B5EB155

          Java雜家

          雜七雜八。。。一家之言

          BlogJava 首頁 新隨筆 聯系 聚合 管理
            40 Posts :: 1 Stories :: 174 Comments :: 0 Trackbacks
          如果Web服務器需要頻繁傳送文件給客戶端時,大多數web容器會提供異步發送的支持,像IIS中的通過ServerSupportFunction(),Apache里面apr_sendfile(),Tomcat6.X通過設置Servlet Request的請求屬性等等。。。都可以做到異步發送文件,從而提高服務器性能。

          Jetty6.X默認也不提供相關支持,本文提供一種hack方法,僅供參考:

          先看測試Servlet:
          package com.yovn.labs.testweb;

          import java.io.File;
          import java.io.IOException;

          import javax.servlet.ServletException;
          import javax.servlet.http.HttpServlet;
          import javax.servlet.http.HttpServletRequest;
          import javax.servlet.http.HttpServletResponse;

          import com.yovn.labs.sendfile.JettySendFile;
          import com.yovn.labs.sendfile.NormalSendFile;
          import com.yovn.labs.sendfile.SendFile;

          /**
           * 
          @author yovn
           *
           
          */
          public class SendFileServlet extends HttpServlet {

              
          protected void doGet(HttpServletRequest req, HttpServletResponse res)
                      
          throws ServletException, IOException {
              
                  
                  
          try {
                      
                      File f
          =new File("D:\\workspace\\TEST.rar");//about 45M
                      String action
          =req.getParameter("action");
                      SendFile sf
          =null;
                      
          if("1".equals(action))
                      {
                          sf
          =new JettySendFile();
                      }
                      
          else
                      {
                          sf
          =new NormalSendFile();
                      }
                      
          long start=System.currentTimeMillis();
                      sf.doSend(req, res, f, 
          null);
                      System.out.println(
          " service ok, action="+action+",use:"+(System.currentTimeMillis()-start)+"!!!");
                  } 
          catch (Exception e) {
                      
          throw new ServletException(e);
                  }
                
              }
              
              

          }
          代碼很簡單明了,action=1時使用Jetty的異步發送,action=2時使用正常方式。

          下面是通過firefox直輸入地址回車后,下載文件,后臺的程序運行結果:
           service ok, action=1,use:62!!!
           service ok, action
          =2,use:10688!!!
           service ok, action
          =2,use:9063!!!
           service ok, action
          =1,use:47!!!
          當運行1時,實際上客戶端還沒有下完文件,但是該段代碼已經執行完了,IO的操作是異步的。
          當運行2時,客戶端下完代碼才執行完。

          以下是Jetty異步發送的代碼:
          package com.yovn.labs.sendfile;

          import java.io.File;
          import java.io.IOException;
          import java.lang.reflect.Field;

          import javax.servlet.http.HttpServletRequest;
          import javax.servlet.http.HttpServletResponse;

          import org.mortbay.io.EndPoint;
          import org.mortbay.io.nio.NIOBuffer;

          /**
           * 
          @author yovn
           *
           
          */
          public class JettySendFile implements SendFile {

              
          static Field endpointField=null;
              
          static Class reqCls=null;
              
          static 
              {
                  
          try {
                      reqCls
          =Class.forName("org.mortbay.jetty.Request");
                      endpointField
          =reqCls.getDeclaredField("_endp");
                      endpointField.setAccessible(
          true);
                  } 
          catch (Exception e) {
                      
          // TODO Auto-generated catch block
                      e.printStackTrace();
                  } 
              }
                  
              
              


              
          public void doSend(HttpServletRequest req, HttpServletResponse res,File todo,String headerOpt)
                      
          throws IOException {
                  
                  
          if(endpointField==null)throw new IOException("Jetty Not Available!!");
                  
          if(!req.getClass().equals(reqCls))
                  {
                      
          throw new IOException("Not in Jetty Context!!");
                  }
                  EndPoint ep;
                  
          try {
                      ep 
          = (EndPoint)endpointField.get(req);
                  
                      
          if(headerOpt==null)
                      {
                          headerOpt
          ="HTTP/1.1 200 OK \r\nContent-Type: APPLICATION/OCTET-STREAM\r\n"+
                                
          "Content-Disposition: attachment;filename=\""+todo.getName()+"\"\r\n"+
                                
          "Content-Length: "+todo.length()+"\r\n\r\n";
                      }
                      
          byte[] headerBytes=headerOpt.getBytes("UTF-8");
                      NIOBuffer header
          =new NIOBuffer(headerBytes.length,false);
                      header.put(headerBytes);
                      
                      NIOBuffer buffer
          =new NIOBuffer(todo);
                      
                      ep.flush(header, buffer, 
          null);
                  } 
          catch (IllegalArgumentException e) {
                      
          throw new IOException(e);
                  } 
          catch (IllegalAccessException e) {
                      
          throw new IOException(e);
                  }
                  
                  
                  
              }

          }

          正常發送文件的代碼:
          package com.yovn.labs.sendfile;

          import java.io.File;
          import java.io.FileInputStream;
          import java.io.IOException;
          import java.io.InputStream;
          import java.io.OutputStream;

          import javax.servlet.http.HttpServletRequest;
          import javax.servlet.http.HttpServletResponse;

          /**
           * 
          @author yovn
           *
           
          */
          public class NormalSendFile implements SendFile {

              
          /* (non-Javadoc)
               * We simply ignore the 'headerOpt'
               * @see com.yovn.labs.sendfile.SendFile#doSend(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse, java.io.File, java.lang.String)
               
          */
              
          public void doSend(HttpServletRequest req, HttpServletResponse res,
                      File todo, String headerOpt) 
          throws IOException {
                  res.setHeader(
          "Content-Type""APPLICATION/OCTET-STREAM");
                  res.setHeader(
          "Content-Disposition""attachment;filename=\""+todo.getName()+"\"");
                  res.setHeader(
          "Content-Length", todo.length()+"");
                  res.setStatus(HttpServletResponse.SC_OK);
                  OutputStream out
          =res.getOutputStream();
                  InputStream in
          =new FileInputStream(todo);
                  
                  
          byte[] buffer=new byte[8192];
                  
                  
          int read=0;
                  
          while((read=in.read(buffer))>0)
                  {
                      out.write(buffer, 
          0, read);
                  }
                  out.flush();
                  in.close();
                  
                  

              }

          }


          posted on 2008-03-29 01:54 DoubleH 閱讀(1770) 評論(0)  編輯  收藏

          只有注冊用戶登錄后才能發表評論。


          網站導航:
           
          主站蜘蛛池模板: 蒙阴县| 镇江市| 溧水县| 固安县| 巴青县| 肇东市| 开平市| 同仁县| 韶山市| 甘泉县| 翁牛特旗| 梓潼县| 阿勒泰市| 文安县| 桐庐县| 土默特左旗| 泉州市| 清流县| 宜兰县| 白朗县| 三门峡市| 铜鼓县| 浑源县| 弥勒县| 安达市| 米泉市| 姚安县| 方正县| 谢通门县| 怀安县| 贡嘎县| 松江区| 北流市| 山东| 福安市| 宾阳县| 南华县| 合川市| 兴义市| 成都市| 泰安市|