IT/운영체제 / / 2015. 3. 26.

[tmax] 파일 다운로드 관련 부분 참고

포스팅 목차


    "webtob1_portal-hth0(localhost:9900)-w20 [container1-33]" prio=1 tid=0x08c0a908 nid=0x2e81 runnable [0x3fa31000..0x3fa31da0]
            at jeus.servlet.engine.io.FullBufferedOutputAdaptor.prepareBuffer(FullBufferedOutputAdaptor.java:55)
            at jeus.servlet.engine.io.ProtocolOutputAdaptor.write(ProtocolOutputAdaptor.java:183)
            at jeus.servlet.engine.io.WebServerOutputStream.write(WebServerOutputStream.java:575)
            at java.io.BufferedOutputStream.flushBuffer(BufferedOutputStream.java:65)
            at java.io.BufferedOutputStream.write(BufferedOutputStream.java:109)
            - locked <0x73bfd5a8> (a java.io.BufferedOutputStream)
            at com.dq.jdf.file.FileUtil.fileDown(FileUtil.java:512)
            at com.dq.jdf.file.DownloadServlet.service(DownloadServlet.java:56)
            at javax.servlet.http.HttpServlet.service(HttpServlet.java:856)
            at jeus.servlet.engine.ServletWrapper.executeServlet(ServletWrapper.java:313)
            at jeus.servlet.filter2.FilterChainImpl.internalDoFilter(FilterChainImpl.java:139)
            at jeus.servlet.filter2.FilterChainImpl.doFilter(FilterChainImpl.java:91)
            at com.dq.jdf.jsp.CharacterEncodingFilter.doFilter(CharacterEncodingFilter.java:81)
            at com.dq.gcms.web.HibernateTransactionFilter.doFilter(HibernateTransactionFilter.java:43)
            at jeus.servlet.filter2.FilterChainImpl.internalDoFilter(FilterChainImpl.java:122)
            at jeus.servlet.filter2.FilterChainImpl.doFilter(FilterChainImpl.java:91)
            at jeus.servlet.engine.ServletWrapper.execute(ServletWrapper.java:195)
            at jeus.servlet.engine.WebtobRequestProcessor.run(WebtobRequestProcessor.java:181)


    - 이건 어느 사이트 부분 쓰레드 덤프중 일부이다. 물론 장애 발생시 바로 덤프를 떳어야 했는데 그러지 못해서 
    정확한 원인 분석은 할수 없었다. 하지만, 이부분은 참고적으로 알고 있어야 하는 부분 같아서 두서 없이 적어봅니다.
     네트웍 지식이 없으니..솔직히 잘 모르겠지만~ 그래도 들은대로 잘 기억해서 설명해 본다.

    1. 파일 전송 부분 관련된것 중  http프로토콜이 있다. 예전 브라우저에선 HTTP1.0을 사용하였으나, 
    요즘 브라우저에서는 HTTP1.1을 기본을 사용하게끔 되어 있다. 확인하고 싶으면 인터넷옵션쪽에 고급부분에가서 
    확인해보면 체크되어 있는걸 확인할 수 있다. 
    문제는 이 프로토콜 전송에 관련된 방식중에서 chuncked 방식과 fullbuffered 방식이 있다. 물론 이름만 보면 
    다들 머리가 좋으니깐 대충 짐작하겠지만.. 대충 설명을 해보면, 예를 들어 10MB 용량을 가진 파일을 전송한다 했을때, 
    chunked방식은 10MB를 기본 8K로 나누어서 전송하는 방식이고, fullbuffered 방식은 10MB전체를 버퍼에 저장하여 
    전송하게 된다. 물론 유저가 몇 안될때는 괜찮겠지만, 유저가 많아지게 된다면, 메모리사용량도 올라갈 것이고, 
    심각하면... 모두 알것이다. 장애 직후 덤프를 뜬게 아니어서, 양양의 사이트의 죽는 원인은 잘은 모르겠지만, 이부분이 
    한번 걸렸기 때문에 확인을 바란다고 했다. 하지만 예전에 문제없이 돌아가던 사이트고 , 소스를 건드린적이 없는데 
    이런 현상이 일어날수 있는지 물어보니깐, 티멕스쪽에서도 물론 정확한 원인이 아니고, 이런 부분이 한번 발견되었기 
    때문에 한번 확인을 해보라고 말을 해드리는거라고 했다.

    2. 제우스 설정 부분에서 파일 전송관련된 설정이 있다. 제우스 설정 파일을 보면 라인중에서 아래의 설정 값을 찾을수 있다.

     output-buffer-size 8152

    - 현재는 8k로 설정되어 있다. 이부분은 파일 전송시 1번 HTTP 관련 전송 프로토콜을 타고나서 제우스 설정을 거쳤을때 
    하는 설정부분인데, 이 설정 값이 만약에 0으로 설정되어 있다면, 위에서 말한 fullbuffered 방식을 따른다고 한다. 
    하지만 양양은 8k로 설정 되어있기 때문에 제우스 설정문제는 아니라는것이다.

    3. 마지막으로 응용프로그램단의 문제이다. 응용프로그램단에 친절하게 잘못된 소스와 수정한 소스를 같이 보여주셨다. 
    물론 다른 쪽 지원을 하다 남겨두신 소스라고 한다. 하지만 잘 모르겠다는.... ㅡㅡ;;;

    1) 잘못된 소스의 예이다.  

    private void transport(InputStream in, OutputStream out, File file) throws IOException {
                
      BufferedInputStream bin = null;
      BufferedOutputStream bos = null;
            
      try {
       bin = new BufferedInputStream(in);
       bos = new BufferedOutputStream(out);
            
       byte[] buf = new byte[(int)file.length()];  <== 잘못된 부분. 파일 크기만큼 메모리적재
       int read = 0;
       while ((read = bin.read(buf)) != -1) {
        bos.write(buf,0,read);
       }
      } finally {
       bos.close();
       bin.close();
      }
     }


    2)  수정된 부분의 소스.  

    <%@ page contentType="text/html;charset=euc-kr"%>
    <%@ page import="java.io.*"%>
    <%@ page import = "javax.servlet.http.*"%>
    <%
            String filename         = request.getParameter("filename")== null ? "" : request.getParameter("filename");
            filename = new String( filename.getBytes("8859_1"), "euc-kr" );
            String savePath = "/gdportal1/webhome/servlet_home/jsp/TBOARD/Files/"; //저장경로 지금은 unix 상태의 경로
            //out.println(filename);
            File file = new File(savePath + filename);
            //byte b[] = new byte[(int)file.length()];
            byte b[] = new byte[4096];  => 4k 씩 나눠서 전송한다는...
            //response.setContentType( "application/octet-stream;charset=euc-kr" );
            //response.setHeader("Content-Disposition", "attachment;filename="+filename);
            response.setHeader("Content-Disposition", "attachment; filename=" + filename + ";");
            response.setContentLength(file.length()); <== fullbeffered 방식으로 동작할때는 setContentLength 가 설정되어 있어야 한다. 그렇지 않으면 파일크기를 알 수 없어 계속 기다림
            //out.println(file.isFile()+","+file.length());
            if (file.isFile() && file.length() > 0){
                    try{
                            BufferedInputStream fin = new BufferedInputStream(new FileInputStream(file));
                            BufferedOutputStream outs = new BufferedOutputStream(response.getOutputStream());
                            int read = 0;
                            while ((read = fin.read(b)) != -1){
                                    outs.write(b,0,read);
                            }
                            outs.flush();
                            outs.close();
                            fin.close();
                    }
                    catch(Exception e){
                    }
                    out.clear();
                    out = pageContext.pushBody();
            }else{
            }
    %>

     


    • 네이버 블로그 공유
    • 네이버 밴드 공유
    • 페이스북 공유
    • 카카오스토리 공유