How to get an existing websocket instance

前端 未结 2 777
礼貌的吻别
礼貌的吻别 2020-12-24 03:12

I\'m working on an application that uses Websockets (Java EE 7) to send messages to all the connected clients asynchronously. The server (Websocket endpoint) should send the

2条回答
  •  时光取名叫无心
    2020-12-24 04:09

    The container creates a separate instance of the endpoint for every client connection, so you can't do what you're trying to do. But I think what you're trying to do is send a message to all the active client connections when an event occurs, which is fairly straightforward.

    The javax.websocket.Session class has the getBasicRemote method to retrieve a RemoteEndpoint.Basic instance that represents the endpoint associated with that session.

    You can retrieve all the open sessions by calling Session.getOpenSessions(), then iterate through them. The loop will send each client connection a message. Here's a simple example:

    @ServerEndpoint("/myendpoint")
    public class MyEndpoint {
      @OnMessage
      public void onMessage(Session session, String message) {
        try {  
          for (Session s : session.getOpenSessions()) {
            if (s.isOpen()) {
              s.getBasicRemote().sendText(message);
            }
        } catch (IOException ex) { ... }
      } 
    } 
    

    But in your case, you probably want to use CDI events to trigger the update to all the clients. In that case, you'd create a CDI event that a method in your Websocket endpoint class observes:

    @ServerEndpoint("/myendpoint")
    public class MyEndpoint {
      // EJB that fires an event when a new article appears
      @EJB
      ArticleBean articleBean;
      // a collection containing all the sessions
      private static final Set sessions = 
              Collections.synchronizedSet(new HashSet());
    
      @OnOpen
      public void onOpen(final Session session) {
        // add the new session to the set
        sessions.add(session);
        ...
      }
    
      @OnClose
      public void onClose(final Session session) {
        // remove the session from the set
        sessions.remove(session);
      }
    
      public void broadcastArticle(@Observes @NewArticleEvent ArticleEvent articleEvent) {
        synchronized(sessions) {
          for (Session s : sessions) {
            if (s.isOpen()) {
              try {
                // send the article summary to all the connected clients
                s.getBasicRemote().sendText("New article up:" + articleEvent.getArticle().getSummary());
              } catch (IOException ex) { ... }
            }
          }
        }
      }
    }
    

    The EJB in the above example would do something like:

    ...
    @Inject
    Event newArticleEvent;
    
    public void publishArticle(Article article) {
      ...
      newArticleEvent.fire(new ArticleEvent(article));
      ...
    }
    

    See the Java EE 7 Tutorial chapters on WebSockets and CDI Events.

    Edit: Modified the @Observer method to use an event as a parameter.

    Edit 2: wrapped the loop in broadcastArticle in synchronized, per @gcvt.

    Edit 3: Updated links to Java EE 7 Tutorial. Nice job, Oracle. Sheesh.

提交回复
热议问题