2014-10-16 31 views
9

Przeglądałem wiele przykładów Web Socket, slajdów prezentacji i koncentrują się one głównie na dość prostych scenariuszach, w których klient-serwer inicjuje komunikację.Jak zaimplementować funkcję push to client za pomocą Java EE 7 WebSockets?

Jestem zainteresowany innym scenariuszem, który wydaje się równie praktyczny: czysty serwer push do klienta.

Przykład Mam na myśli aplikację, która aktualizuje wartość akcji na stronie internetowej. Wyobraź sobie, że istnieje zewnętrzny system giełdowy, który wysyła wiadomość JMS dla każdej subskrybowanej zmiany wartości akcji.

Chciałbym wiedzieć, jak przetłumaczyć takie przychodzące zdarzenie JMS na serwer i wypchnąć go efektywnie i idiomatycznie z perspektywy Java EE 7.

O ile mogę zrozumieć, spec, ja powinienem napisać końcowy websocket

@ServerEndpoint("/demo") 
public class WSEndpoint { 
    private static final Logger LOG = Logger.getLogger(WSEndpoint.class); 

    @OnMessage 
    public void onMessage(String message, Session session) { 
    LOG.info("Received : " + message + ", session:" + session.getId()); 
    } 

    @OnOpen 
    public void open(Session session) { 
    LOG.info("Open session:" + session.getId());   
    } 

    @OnClose 
    public void close(Session session, CloseReason c) { 
    log.info("Close session:" + session.getId()); 
    } 
} 

wszystko jest łatwe, kiedy ja dostaję wiadomość od frontend, mogę robić co mi się podoba w @OnMessage metoda. Ale w moim przykładzie nie otrzymam żadnej wiadomości od klienta, dostanę zdarzenie z jakiegoś zewnętrznego systemu.

Istnieje kilka podejść. Na przykład mogę utworzyć wątek w metodzie @OnOpen, jak pokazano w this blog. W praktyce takie podejście może wskazywać na niedociągnięcie, ponieważ dla każdego klienta będę potrzebował stworzyć nowy, potencjalnie długotrwały wątek.

Można zrobić lepiej, używając kanałów NIO z selektorami, ale wymagałoby to pewnego rodzaju "ręcznego" zarządzania kanałami. Naprawalne, ale raczej niewygodne.

Innym rozwiązaniem byłoby pingowanie innego systemu do aktualizacji, ale znowu byłoby to trochę brzydkie. Ponadto nie jestem również pewien, czy metoda ta ma być używana w ten sposób.

Najlepiej, aby przychodząca wiadomość JMS spowodowała naciśnięcie przycisku Web Socket do klienta. Jakieś pomysły jak ładnie zaimplementować coś takiego?

+1

https://blogs.oracle.com/brunoborges/entry/integrating_websockets_and_jms_with –

+0

Dzięki za link. To wygląda całkiem nieźle (w punkcie 7 jest faktyczna implementacja push). Robi się to w następujący sposób: musimy stworzyć zestaw wszystkich sesji (statyczny zestaw synchronizowany). Następnie, jeśli chcemy wysłać do klienta push, przechodzimy przez ten zestaw i naciskamy spust. Jest kilka wad tego podejścia, ale nic, co nie może zostać przezwyciężone. –

+0

Nasze pytanie jest mocno powiązane: https://stackoverflow.com/questions/27037570/find-websocket-session-by-id-in-java-ee-7/27045235 – Ihromant

Odpowiedz

4

Prawdopodobnie nie jest to najbardziej elegancki sposób, ale tylko po to, aby zademonstrować pomysł. Metoda broadcast() wyśle ​​wiadomość do wszystkich podłączonych klientów.

@ServerEndpoint("/echo") 
public class ServerEndPoint { 

    private static Set<Session> userSessions = Collections.newSetFromMap(new ConcurrentHashMap<Session, Boolean>()); 

    @OnOpen 
    public void onOpen(Session userSession) { 
     userSessions.add(userSession); 
    } 

    @OnClose 
    public void onClose(Session userSession) { 
     userSessions.remove(userSession); 
    } 

    @OnMessage 
    public void onMessage(String message, Session userSession) { 
     broadcast(message); 
    } 

    public static void broadcast(String msg) { 
     for (Session session : userSessions) { 
      session.getAsyncRemote().sendText(msg); 
     } 
    } 

} 
+0

lepiej używać metody getAsyncRemote() lub getBasicRemote()? –

1

zrobić to w ten sposób (nie żądanie klienta jest potrzebne):

@ServerEndpoint("/hello") 
public class HelloWebSocket { 

    @OnOpen 
    public void greetTheClient(Session session){ 
     try { 
     session.getBasicRemote().sendText("Hello stranger"); 

    } catch (IOException ioe) { 
     System.out.println(ioe.getMessage()); 
    } 
    } 
}