Ограничить количество клиентов, которые могут подключиться к серверу одновременно - PullRequest
0 голосов
/ 09 мая 2019

Мне нужно ограничить количество клиентов, которые могут подключаться к серверу. Я хочу, чтобы только 5 клиентов могли подключаться. Когда 6-й клиент попытается подключиться, он будет добавлен в очередь. Как только один из клиентов уходит, вызывается .remove, он идет в очередь и получает первого ожидающего клиента и подключает его к чату.

    public void start() {
    keepGoing = true;
    /* create socket server and wait for connection requests */
    try 
    {
        // the socket used by the server
        ServerSocket serverSocket = new ServerSocket(port);

        // infinite loop to wait for connections
        while(keepGoing) 
        {
            // format message saying we are waiting
            display("Server waiting for Clients on port " + port + ".");

            Socket socket = serverSocket.accept();      // accept connection
            // if I was asked to stop
            if(!keepGoing)
                break;
            ClientThread t = new ClientThread(socket);  // make a thread of it
            al.add(t);                                  // save it in the ArrayList
            t.start();
        }
        // I was asked to stop
        try {
            serverSocket.close();
            for(int i = 0; i < al.size(); ++i) {
                ClientThread tc = al.get(i);
                try {
                tc.sInput.close();
                tc.sOutput.close();
                tc.socket.close();
                }
                catch(IOException ioE) {
                    // not much I can do
                }
            }
        }
        catch(Exception e) {
            display("Exception closing the server and clients: " + e);
        }
    }
    // something went bad
    catch (IOException e) {
        String msg = sdf.format(new Date()) + " Exception on new ServerSocket: " + e + "\n";
        display(msg);
    }
}   

Чтобы отправить сообщение всем клиентам:

    private synchronized void broadcast(String message) {
    // add HH:mm:ss and \n to the message
    String time = sdf.format(new Date());
    String messageLf = time + " " + message + "\n";
    // display message on console or GUI
    if(sg == null)
        System.out.print(messageLf);
    else
        sg.appendRoom(messageLf);     // append in the room window

    // we loop in reverse order in case we would have to remove a Client
    // because it has disconnected
    for(int i = al.size(); --i >= 0;) {
        ClientThread ct = al.get(i);
        // try to write to the Client if it fails remove it from the list
        if(!ct.writeMsg(messageLf)) {
            al.remove(i);
            display("Disconnected Client " + ct.username + " removed from list.");
          }
      }
  }

Для клиента, который выходит из системы с помощью сообщения ВЫХОД:

    synchronized void remove(int id) {
    // scan the array list until we found the Id
    for(int i = 0; i < al.size(); ++i) {
        ClientThread ct = al.get(i);
        // found it
        if(ct.id == id) {
            al.remove(i);
            return;
        }
    }
}

1 Ответ

1 голос
/ 09 мая 2019

Самый простой способ принять только определенное количество клиентов и поставить в очередь остальных - прекратить прослушивание клиентов после достижения предела.

ServerSocket уже имеет очередь, поэтому, если вы прекратите прослушивание, чрезмерные запросы все равно автоматически ставятся в очередь. Чтобы управлять размером очереди, используйте конструктор ServerSocket(int port, int backlog):

[...]

Максимальная длина очереди для индикации входящего соединения (запрос на подключение) задается параметром backlog. Если индикация соединения появляется, когда очередь заполнена, соединение отклоняется.

[...]

Параметры:

port - номер порта или 0 для использования номера порта, который назначается автоматически.

backlog - запрашиваемая максимальная длина очереди входящих соединений.

Итак, если количество запущенных клиентских потоков ограничено, не звоните serverSocket.accept(). Дождитесь завершения потока клиента, прежде чем основной поток снова вызовет accept().

Самым простым способом управления является использование Semaphore с заданным пределом потока в качестве числа разрешений , то есть основной поток вызывает acquire() перед вызовом accept(), и клиентский поток вызывает release() из блока finally до его окончания.

Подсказка: производительность можно повысить, если использовать пул потоков вместо запуска нового потока для каждого запроса.

...