자바 SSE 서버 푸 시 WEB 페이지 수신 데이터

16714 단어 자바sse웹 개발
  
, web app, , , , , : -- , , 、 , , Web , ,Web , , , 。 , 。
, :
1.
2. ,



、Ajax

Ajax , Ajax , ajax , 。
, , , 。
JSONP , , , 。



, , , , , 。

、Comet

Comet, HTTP " " , , , :
1. AJAX (long-polling)
Ajax JavaScript XMLHttpRequest HTTP ,JavaScript HTML 。 AJAX " " AJAX :

JavaScript , , 。
、 , ; , 。



" "(poll), " "(pull)。 AJAX, : ; ;IE、Mozilla FireFox AJAX。
(long polling) , HTTP XHR :
(1). HTTP JSONP
script 。 , , script , 。
(2).XHR

AJAX ; , , 。 JavaScript , , ; 。
CROS , HTTP JSONP , XHR 。

, Ajax 。

。 , , 。
>> , : Ajax , 。 : 。 : , 。 : 。 : Ajax , hold , , 。 : 。 : hold 。 :WebQQ、Hi 、Facebook IM。 , socket : : iframe, iframe src , 。 : , 。 : 。 :Gmail Flash Socket: Socket Flash JavaScript Flash Socket Socket ,JavaScript 。 : , 。 : Flash ; HTTP , 。 : 。
2. Iframe htmlfile (streaming)
iframe HTML , HTML , SRC , 。



Comet
: ( ); ( )
: , 。
Comet
1. Dojo CometD —— http://cometdproject.dojotoolkit.org/
2. DWR —— http://directwebremoting.org/dwr/index.html
3. ICEfaces —— http://www.icefaces.org/main/home/
4. GlassFish Grizzly —— https://grizzly.dev.java.net/
CometD Comet , DWR 。 ICEfaces , 。 Grizzly GlassFish , 。CometD, DWR 。
Comet
HTTP
IE , Web , 。 , 。 HTTP 1.1 , HTTP , 。 IE 。
HTTP 1.1 , Web : IE Web , IE HTTP 。
, frame , frame HTTP , HTTP , frame 。

Web , Comet, 。 , ; 。
, 。HTTP 1.1 1.0 :1.0 Get/Post ; 1.1 , , 。 Java 1.4 IO java.nio 。 , , ; , 。 、 。
AJAX , Comet , , 。Jetty 6 Web AJAX、Comet 。
HTTP
, : , , 。 , , 。
, HTTP , 。
, iframe , iframe, , , , ; , 。 AJAX , XMLHttpRequest , 。
“ ”
: , 。 , , 。 。 :
, , 。 , , 。
AJAX ; 、 , , , 、 。
, , 、 。

,websocket
WebSocket HTML5 TCP 。WebSocket 2011 IETF RFC 6455,WebSocketAPI W3C 。 WebSocket API , , , 。 。


websocket , websocket , 。

, 。


sse java

//
package com.xy.inuyasha.web.controller;

import javax.servlet.AsyncContext;
import javax.servlet.AsyncEvent;
import javax.servlet.AsyncListener;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Date;

/**
* Created by Administrator on 2017/3/15.
*/
@WebServlet(urlPatterns = { "/role_echo" }, asyncSupported = true)
public class SseTest extends HttpServlet {

   private static final long serialVersionUID = 1L;
   private final static int DEFAULT_TIME_OUT = 10 * 60 * 1000;

   @Override
   protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
       // TODO Auto-generated method stub
       resp.setContentType("text/event-stream");
       resp.setCharacterEncoding("UTF-8");
       req.setAttribute("org.apache.catalina.ASYNC_SUPPORTED", true);//

       AsyncContext actx = req.startAsync(req, resp);
       actx.setTimeout(DEFAULT_TIME_OUT);
       actx.addListener(new AsyncListener() {
           @Override
           public void onComplete(AsyncEvent arg0) throws IOException {
               // TODO Auto-generated method stub
               System.out.println("[echo]event complete:" + arg0.getSuppliedRequest().getRemoteAddr());
           }

           @Override
           public void onError(AsyncEvent arg0) throws IOException {
               // TODO Auto-generated method stub
               System.out.println("[echo]event has error");
           }

           @Override
           public void onStartAsync(AsyncEvent arg0) throws IOException {
               // TODO Auto-generated method stub
               System.out.println("[echo]event start:" + arg0.getSuppliedRequest().getRemoteAddr());
           }

           @Override
           public void onTimeout(AsyncEvent arg0) throws IOException {
               // TODO Auto-generated method stub
               System.out.println("[echo]event time lost");
           }
       });
       new Thread(new AsyncWebService(actx)).start();
   }
}

class AsyncWebService implements Runnable {
   AsyncContext ctx;

   public AsyncWebService(AsyncContext ctx) {
       this.ctx = ctx;
   }

   public void run() {
       try {
           // ,
           Thread.sleep(10000);
           PrintWriter out = ctx.getResponse().getWriter();
           out.println("data: " + new Date() + "\r
");  //js EventSource :data: + "\r
"

           out.flush();
            ctx.complete();
       } catch (Exception e) {
           e.printStackTrace();
       }

   }

}
//jsp js
if (!!window.EventSource) { //EventSource SSE    .         EventSource  
   var source = new EventSource('/role_echo');//
    s = '';

   source.addEventListener('message', function(e) {
      
         s += e.data + "
";
       $("#msgFromPush").html(s);
   },false);//

   source.addEventListener('open', function(e) {
       console.log(" ");
   }, false);

   source.addEventListener('error',function(e){
       if(e.currentTarget.readyState==EventSource.CLOSED){
           console.log(" ");
       }else{
           console.log(e.currentTarget.readyState);
       }
   });
}else{
   console.log(" SSE");
}

!!

웹 소켓
인터넷 이 발전 함 에 따라 전통 적 인 HTTP 프로 토 콜 은 웹 응용 이 날로 복잡 해 지 는 수 요 를 만족 시 키 기 어렵다.최근 몇 년 동안 HTML 5 가 탄생 하면 서 웹 소켓 프로 토 콜 은 브 라 우 저 와 서버 의 모든 양 방향 통신 을 실현 하고 브 라 우 저 와 서버 의 통신 기능 을 확대 하여 서버 도 자발적으로 클 라 이언 트 에 데 이 터 를 보 낼 수 있 도록 했다.
우 리 는 전통 적 인 HTTP 프로 토 콜 이 무상 태 라 는 것 을 알 고 있 습 니 다. 매번 요청 (request) 은 클 라 이언 트 (예 를 들 어 브 라 우 저) 가 주동 적 으로 시작 해 야 합 니 다. 서버 가 처리 한 후에 response 결 과 를 되 돌려 주 고 서버 는 클 라 이언 트 에 데 이 터 를 주동 적 으로 보 내기 어렵 습 니 다.이러한 클 라 이언 트 는 주동 적 인 측 이 고 서비스 측은 수 동적 인 측의 전통 적 인 웹 모델 로 정보 변화 가 빈번 하지 않 은 웹 응용 에 있어 발생 하 는 번 거 로 움 이 비교적 적 으 며 실시 간 정보 와 관련 된 웹 응용 에 큰 불편 을 가 져 왔 다. 예 를 들 어 실시 간 통신, 실시 간 데이터, 구독 푸 시 등 기능 을 가 진 응용 이다.웹 소켓 규범 이 제기 되 기 전에 개발 자 들 은 이러한 실시 간 으로 비교적 강 한 기능 을 실현 하려 면 절충 적 인 해결 방법 인 폴 링 (polling) 과 Comet 기술 을 자주 사용한다.사실 후 자 는 본질 적 으로 도 일종 의 폴 링 으로 개선 되 었 을 뿐이다.
폴 링 은 실시 간 웹 응용 을 실현 하 는 가장 원시 적 인 해결 방안 이다.폴 링 기술 은 클 라 이언 트 가 설정 한 시간 간격 으로 주기 적 으로 서버 에 요청 을 보 내 고 새로운 데이터 변경 여 부 를 자주 조회 하도록 요구한다.이런 방법 은 불필요 한 요청 을 너무 많이 하고 데이터 와 서버 자원 을 낭비 하 는 것 이 분명 하 다.
Comet 기술 은 긴 폴 링 과 스 트림 기술 로 나 눌 수 있다.긴 폴 링 은 상술 한 폴 링 기술 을 개선 하여 쓸모없는 요 구 를 줄 였 다.일부 데이터 에 만 료 시간 을 설정 하고 데이터 가 만 료 된 후에 야 서버 에 요청 을 보 낼 수 있 습 니 다.이런 메커니즘 은 데이터 의 변경 에 적합 하 다. 특별히 빈번 한 상황 은 아니다.스 트림 기술 은 클 라 이언 트 가 숨겨 진 창 을 사용 하여 서버 와 HTTP 긴 연결 을 만 드 는 것 을 말 합 니 다. 서버 는 연결 상 태 를 계속 업데이트 하여 HTTP 긴 연결 을 유지 합 니 다.이렇게 하면 서버 는 이 긴 연결 을 통 해 자발적으로 데 이 터 를 클 라 이언 트 에 보 낼 수 있다.스 트림 기술 은 병발 환경 에서 서버 의 성능 을 시험 할 수 있다.
이 두 가지 기술 은 모두 요청 - 응답 모델 을 바탕 으로 하 는 것 으로 진정한 의미 의 실시 간 기술 이 아니다.그들의 모든 요청, 응답 은 똑 같은 머리 정보 에 일정한 데 이 터 를 낭비 하고 개발 의 복잡 도 도 비교적 크다.
HTML 5 가 출시 한 웹 소켓 과 함께 웹 의 실시 간 통신 을 진정 으로 실현 하여 B / S 모드 가 C / S 모드 의 실시 간 통신 능력 을 갖 추 게 되 었 다.웹 소켓 의 작업 절 차 는 다음 과 같 습 니 다. 브 라 우 저 는 자바 스 크 립 트 를 통 해 서버 에 웹 소켓 연결 을 요청 합 니 다. 웹 소켓 연결 이 성공 하면 클 라 이언 트 와 서버 는 TCP 연결 을 통 해 데 이 터 를 전송 할 수 있 습 니 다.웹 소켓 연결 은 본질 적 으로 TCP 연결 이기 때문에 전송 할 때마다 반복 되 는 머리 데 이 터 를 가 져 올 필요 가 없 기 때문에 폴 링 과 Comet 기술 보다 데이터 전 송 량 이 훨씬 적다.본 고 는 웹 소켓 규범 을 상세 하 게 소개 하지 않 고 주로 웹 소켓 이 자바 웹 에서 의 실현 을 소개 한다.
자바 EE 7 에서 JSR - 356: 자바 API for WebSocket 규범 이 나 왔 습 니 다.Tomcat, Nginx, Jetty 등 많은 웹 용기 들 이 웹 소켓 을 지원 한다.톰 캣 은 7.0.27 부터 웹 소켓 을 지원 하고 7.0.47 부터 JSR - 356 을 지원 하 며, 아래 데모 코드 역시 톰 캣 7.0.47 이상 에 배 치 된 버 전이 있어 야 실행 할 수 있다.
2. WebSocket 예제
2.1. 새 자바 웹 테스트 항목
pom. xml 에 Jar 패키지 의존 추가

javax
javaee-api
7.0
provided

클 라 이언 트 (웹 홈 페이지) 코드:

html>


    Java  WebSocket Tomcat  


    Welcome
         
         
    
    var websocket = null;     // WebSocket     if ('WebSocket' in window) {         websocket = new WebSocket("ws://localhost:8080/websocket");     }     else {         alert('  Not support websocket')     }     //     websocket.onerror = function () {         setMessageInnerHTML("WebSocket ");     };     //     websocket.onopen = function () {         setMessageInnerHTML("WebSocket ");     }     //     websocket.onmessage = function (event) {         setMessageInnerHTML(event.data);     }     //     websocket.onclose = function () {         setMessageInnerHTML("WebSocket ");     }     // , , websocket , ,server 。     window.onbeforeunload = function () {         closeWebSocket();     }     //     function setMessageInnerHTML(innerHTML) {         document.getElementById('message').innerHTML += innerHTML + '<br/>';     }     // WebSocket     function closeWebSocket() {         websocket.close();     }     //     function send() {         var message = document.getElementById('text').value;         websocket.send(message);     }

Java Web后端代码

package me.gacl.websocket;
import java.io.IOException;
import java.util.concurrent.CopyOnWriteArraySet;
import javax.websocket.*;
import javax.websocket.server.ServerEndpoint;
/**
 * @ServerEndpoint            ,                 websocket    ,
 *                    URL  ,         URL    WebSocket    
 */
@ServerEndpoint("/websocket")
public class WebSocketTest {
    //    ,           。            。
    private static int onlineCount = 0;
    //concurrent      Set,            MyWebSocket  。                 ,    Map   ,  Key       
    private static CopyOnWriteArraySet webSocketSet = new CopyOnWriteArraySet();
    //           ,              
    private Session session;
    /**
     *            
     * @param session       。session            ,              
     */
    @OnOpen
    public void onOpen(Session session){
        this.session = session;
        webSocketSet.add(this);     //  set 
        addOnlineCount();           //    1
        System.out.println("      !       " + getOnlineCount());
    }
    /**
     *          
     */
    @OnClose
    public void onClose(){
        webSocketSet.remove(this);  // set   
        subOnlineCount();           //    1
        System.out.println("      !       " + getOnlineCount());
    }
    /**
     *              
     * @param message           
     * @param session      
     */
    @OnMessage
    public void onMessage(String message, Session session) {
        System.out.println("        :" + message);
        //    
        for(WebSocketTest item: webSocketSet){
            try {
                item.sendMessage(message);
            } catch (IOException e) {
                e.printStackTrace();
                continue;
            }
        }
    }
    /**
     *        
     * @param session
     * @param error
     */
    @OnError
    public void onError(Session session, Throwable error){
        System.out.println("    ");
        error.printStackTrace();
    }
    /**
     *               。     ,            。
     * @param message
     * @throws IOException
     */
    public void sendMessage(String message) throws IOException{
        this.session.getBasicRemote().sendText(message);
        //this.session.getAsyncRemote().sendText(message);
    }
    public static synchronized int getOnlineCount() {
        return onlineCount;
    }
    public static synchronized void addOnlineCount() {
        WebSocketTest.onlineCount++;
    }
    public static synchronized void subOnlineCount() {
        WebSocketTest.onlineCount--;
    }
}

1.2. 실행 효과
Google 브 라 우 저 와 불 여우 브 라 우 저 를 동시에 열 어 다 중 클 라 이언 트 시 뮬 레이 션 을 진행 합 니 다. 실행 효 과 는 다음 과 같 습 니 다.

좋은 웹페이지 즐겨찾기