簡體   English   中英

會話管理Jetty Websocket服務器

[英]Session Management Jetty Websocket Server

在一個websocket中收到消息時出現的問題,請將此消息轉發給其他連接的websocket的消息。 我使用jetty-9.2.20.v20161216。

所以我初始化服務器..

JettyWSServer websocketServer = new JettyWSServer("localhost", 8000, new MySocketHandler(), new QueuedThreadPool(128));

public <T extends WebSocketHandler> JettyWSServer(String hostName, int port, T webscoketHandler, QueuedThreadPool threadPool) {
    this.hostName = hostName;
    this.port = port;
    this.handler = webscoketHandler;
    this.threadPool = threadPool;
    this.socket = null;

    //create server
    this.server = new Server(this.threadPool);

    //set connector
    ServerConnector connector = new ServerConnector(server);
    connector.setHost(this.hostName);
    connector.setPort(this.port);
    this.server.addConnector(connector);

    //set handler
    this.server.setHandler(this.handler);

    //set listener
    setLifecycleListener();
}

MySocketHandler.java

public class MySocketHandler extends WebSocketHandler {

    private final String TAG = MySocketHandler.class.getSimpleName();
    private MySocketCreator creator;

    @Override
    public void configure(WebSocketServletFactory webSocketServletFactory) {
        this.creator = new MySocketCreator();
        webSocketServletFactory.setCreator(this.creator);
    }


    public Set<ServerSocket> getSockets(){
        return this.creator.getSockets();
    }
}

MySocketCreator.java

public class MySocketCreator implements WebSocketCreator {

    private static final String TAG = MySocketCreator.class.getSimpleName();
    private static Log log = new Log(TAG, true);

    private Set<ServerSocket> sockets = new HashSet<>();
    private Set<Session> guests = new HashSet<>();
    private ConcurrentHashMap<ServiceUser, ArrayList<WSDeviceSessionWrapper>> users = new ConcurrentHashMap<>();


    @Override
    public Object createWebSocket(ServletUpgradeRequest servletUpgradeRequest, ServletUpgradeResponse servletUpgradeResponse) {
        ServerSocket socket = new ServerSocket(statusCallback);
        sockets.add(socket);
        return socket;
    }


    private OnSessionStatusListener statusCallback = new OnSessionStatusListener() {
        @Override
        public void onGuestIn(Session session) {


            synchronized (this) {
                guests.add(session);
                Integer totalAgeReduce = users.values()
                        .stream()
                        .map(wsDeviceSessionWrappers -> {
                            return 1;
                        })
                        .reduce(
                                0,
                                (a, b) -> a + b);
                log.debug("onGuestIn() " + "Guests: " + guests.size() + " Registered: " + totalAgeReduce);
            }
        }

        @Override
        public void onUserIn(Session session, ServiceUser user, Device device) {


            synchronized (this) {

                if (guests.contains(session)) guests.remove(session);

                if (!users.containsKey(user)) {
                    users.put(user, new ArrayList<WSDeviceSessionWrapper>());
                }
                users.get(user).add(new WSDeviceSessionWrapper(session, device));

                log.debug("onUserIn() " + "Guests: " + guests.size() + " Registered: " + users.size());
            }

        }

        @Override
        public void sendResponse(ArrayList<ServiceUser> users, WSResponse response) {
        log.debug("Send message to [" + (users != null ? users.size() : null) + "] current users " + MySocketCreator.this.users.size());
         MySocketCreator.this.users.keySet().forEach(user -> {
               users.forEach(u -> {
                   if (user.equals(u)) {

                       ArrayList<WSDeviceSessionWrapper> wsDeviceSessionWrappers = MySocketCreator.this.users.get(user);
                       new ArrayList<>(wsDeviceSessionWrappers).forEach(wrapper -> {
                               wrapper.getSession().getRemote().sendStringByFuture(response.toJSON());
                           }
                       });

                   }
               });
           });


        }

        @Override
        public void sendResponse(ServiceUser user, WSResponse response, Device excludeDevice) {
                MySocketCreator.this.users.get(user).forEach(wrapper -> {
                    wrapper.getSession().getRemote().sendStringByFuture(response.toJSON());
                });
        }

        @Override
        public void onExit(Session session, ServiceUser user, Device device) {

            synchronized (this) {

                //remove from guest sessions
                if (session != null && guests.contains(session)) guests.remove(session);


                if (user != null && device != null && users.containsKey(user)) {
                    ArrayList<WSDeviceSessionWrapper> wrappers = users.get(user);
                    Iterator<WSDeviceSessionWrapper> iterator = wrappers.iterator();
                    while (iterator.hasNext()) {
                        WSDeviceSessionWrapper wrapper = iterator.next();
                        if (wrapper.getSession() == session || wrapper.getSession().equals(session) && wrapper.getDevice() == device || wrapper.getDevice().equals(device)) {
                            //remove session for current device
                            iterator.remove();

                            //if user does not have session on server
                            //remove him from current server users
                            if (wrappers.size() == 0) {
                                users.remove(user);
                            }
                        }
                    }
                }

                Integer totalRegisteredDevices = users.values()
                        .stream()
                        .map(wsDeviceSessionWrappers -> {
                            return 1;
                        })
                        .reduce(
                                0,
                                (a, b) -> a + b);
                log.debug("onExit() " + "Guests: " + guests.size() + " Registered: " + totalRegisteredDevices);
            }


        }
    };

    public Set<ServerSocket> getSockets() {
        return sockets;
    }

}

此代碼的邏輯:

MySocketCreator的類中,當創建新的套接字時,我將傳遞給回調。 接下來在onOpen事件中的套接字中,我調用回調並將會話傳遞給該會話,並將該會話存儲在MySocketCreator類中,在此會話之后,我將與用戶和設備關聯。

問題是當我嘗試通過回調方法從任何websocket向所有用戶發送消息時

    @Override
    public void sendResponse(ArrayList<ServiceUser> users, WSResponse response) {
    log.debug("Send message to [" + (users != null ? users.size() : null) + "] current users " + MySocketCreator.this.users.size());
       MySocketCreator.this.users.keySet().forEach(user -> {
           users.forEach(u -> {
               if (user.equals(u)) {
                   ArrayList<WSDeviceSessionWrapper> wsDeviceSessionWrappers = MySocketCreator.this.users.get(user);
                   new ArrayList<>(wsDeviceSessionWrappers).forEach(wrapper -> {
                           wrapper.getSession().getRemote().sendStringByFuture(response.toJSON());
                       }
                   });

               }
           });
       });
    }

字符串wrapper.getSession().getRemote().sendStringByFuture(response.toJSON());

鎖定線程,服務器無法再次工作。 試圖更換它

wrapper.getSession().getRemote().sendString(response.toJSON());

拋出異常

java.lang.IllegalStateException: Blocking message pending 10000 for BLOCKING

org.eclipse.jetty.websocket.api.WebSocketException: RemoteEndpoint unavailable, outgoing connection not open

這兩個選項不適用於300個連接/

問題 :如何向所有用戶發送消息?

您不能盲目地向所有用戶發送消息。

如果某些用戶很擁擠,閱讀速度不如其他用戶怎么辦?

如果一個用戶以比最慢的用戶Internet連接更快的速度生成消息怎么辦?

在您的方案中,您必須處理Future ,然后重新使用sendStringByFuture() (或sendString(String,WriteCallback) ),如果該連接緩慢或失敗,則必須將其從用戶列表中刪除。 如果收到表示已發送郵件的事件,則說明特定的用戶/客戶端不擁擠,可以隨意向其發送其他郵件。

發送的循環必須將每個用戶/客戶端的消息排隊,而不是整體,但是每個用戶/客戶端都有自己的隊列。

僅當已知在發送時該用戶未擁塞時,才必須發送循環。

您甚至可能需要丟棄消息以降低客戶端的速度,或者如果它們的隊列太大,則將它們完全斷開。

是的,這很復雜,這就是為什么在websocket上構建如此多的庫來執行此操作的原因。

考慮使用cometd及其cometd傳輸。

我在具有多個線程的同一Remote上發送消息,然后遇到了相同的異常。

嘗試

wrapper.getSession().getRemote().sendString(msg, new WriteCallback() {
                        @Override
                        public void writeFailed(Throwable x) {

                        }

                        @Override
                        public void writeSuccess() {

                        }
                    });

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM