'놀이!'에 해당되는 글 1건

  1. 2011.06.06 Http Chunked transfer encoding 은 머냐!!
윤Front-End2011.06.06 15:29
자세한 내용은 위키참조 하시고~
http://en.wikipedia.org/wiki/Chunked_transfer_encoding

이번 경험에서 얻었던 내용들을 몇자 적어 볼까 한다. 

경험에 대해서 짧게 이야기 하자면 실시간 통신 그러니까.. 웹브라우저와 서버 간에 통신? 
뭐 Comet 기술 중에 하나로 봐도 되는데.. ie에선 사용을 못하니 어쩜 반쪽짜리 기술이 될 수도 있고.. 
더 많은 실시간 통신 기술에 대해선 2011 JCO 세션중에 실시간 통신과 관련된 내용이 있으니 .. 
기회가 된다면 들어보면 될꺼라고 생각함. 

일단 서버쪽은 예전에 손 놓은 ... JAVA. 
웹쪽은 그냥 jquery조금 사용해서 만들어진 코드. 

고려해야 할 점은.. ajax 이용시 .. XMLHttpRequest 의 readyState 코드가 중요 하다.
코드 내용은 이곳 참조 . 0 부터 4까지 존제 하며 
0은 초기화전. 1은 XMLHttpRequest 가 오픈에 성공했을때 코드. 
2는 서버로 요청 성공시 . 그러나 아직 값은 받지 않았을때.
3. 값을 받고 있을때? 음 processing request라고 해야 하나;;.. 무튼 일단 값을 서버로 부터 받으면 코드가 3으로 바뀜. 
4. 모든게 완료 되면 4번으로 바뀜. 데이터 전송이 완료 되엇을때.. 

그래서 Transfer-Encoding 이 chunked 일 경우 xhr의 코드는 계속 3을 유지 한다. 
아 이녀석은 xhr에 onreadystatechange event에서 확인 하면 되고 .. 그건 요곳 참조. 

지금 까지 정리 하면 서버쪽에서 transfer-encoding이 chunked상태로 보내면 .. 
xhr의 readyState 가 3을 유지... 
그럼 그 상태에서 xhr의 responseText의 값을 확인 해보면 값들이 변경되는 것이 보인다.


하지만 고려해야 할점은... 그동안 보내는 데이터가 계속해서 이어서 나온다는거?! 처음에 a를 보내고 두번째 b를 보냈다면 .. 
1 : responseText => a
2: responseText => a b

이런식으로 계속 온다는 것이다.. 서버에서 end 하기 전까지.. 보통 \r\n을 보내거나.. 랭스가 0인 녀석을 보내면.. 
완료 되엇다고 판단하긴 한다..


그래서 좀 거지 같다.. 매번 데이터를 읽을때 이전 값은 빼고 다시 이번에 새로운 녀석만 읽어 들여야 하니.. 
그리하여 이런 코드가 나온다 ㅡㅡ;;
  xhr.onreadystatechange = function(e) {
    if ((xhr.readyState == 3 || xhr.readyState == 4) && xhr.status == 200 && !isDone) {
      responseText = xhr.responseText;
      responseText = responseText.substring(chunkIdx);
      chunkIdx += responseText.length;
      if(responseText === ''){
        isDone = true;
      }
      if(isJSONString(responseText)){
        updateChat($.parseJSON(responseText));
      }
    }
    if(isDone){
      xhr.abort();
    }
  };


말보단 코드가 더 편한 사람이 있으니..;;  이부분만 해결하면 .. 어느정도 써먹을 순 있다.. 
그리고 지금 처럼 하면 실시간으로 미친듯이 데이터를 받다보면 누적되는 데이터가 장난이 아닐 테니.. 
적당한 길이 봐서 abort시키고 다시 요청 보내서 첨부터 시작하는 프로세스가 필요 할 것이다.. 

자 .. 그럼 서버 코드는?


    @RequestMapping("/chatListener")
    public void chatListener(HttpServletRequest req, HttpServletResponse res, @RequestParam()String uuid) throws Exception {
        ServletOutputStream out = res.getOutputStream();
        try {
            res.setContentType("application/json; charset=utf-8;");
            res.setHeader("Connection", "close");
            chatStore.enterStore(uuid);
            JsonGenerator generator = om.getJsonFactory().createJsonGenerator(res.getOutputStream(), JsonEncoding.UTF8);
            while(true){
                om.writeValue(generator,chatStore.getData(uuid));
                synchronized (this) {
                    wait();
                }
            }
        } catch (Exception e) {
            chatStore.remveStore(uuid);
        } finally {
            if (out != null) {
                try {
                    out.close();
                } catch (Exception e) {
                }
            }
        }
    }


샘플이기 때문에 ㅋ 대충 만들었다..ㅋ 아.. 저기서 json으로 보내려고 다른 녀석을 좀 썼는데 핵심은.. 
out 에서 print메소드를 이용해서 보낼 데이터를 넣구.. 바로 out.flush() 해주는게 핵심이다.
위에 writeValue 메소드에서 그짓을 해준다.. 저녀석은 jacksonjson lib중에 한녀석이구..;; 

무튼 이렇게 해서 대충 실시간을 흉내 낼 순 있다..
ajax를 이용해서 chunked를 읽어 들이려면 readystate코드와 responseText를 파싱하는 ? 이것만 유의하기만 하면 된다. 
서버는 어떻게 자바던 php던 머던.. 스트림을 계속 푸쉬만 해주면 되니까.. :-)

무튼 자세한 설명은 이번 2011 JCO발표를 참고 하시길~~ 발표후에 pt와 코드가 오픈 될테니..;;  


Posted by is윤군