Предельные Связи с семафорами - PullRequest
0 голосов
/ 16 апреля 2010

Я пытаюсь ограничить количество соединений, которые мой сервер будет принимать с использованием семафоров, но при запуске мой код, похоже, не устанавливает это ограничение - правильно ли я использую семафор? например. Я жестко закодировал номер разрешения как 2, но я могу подключить неограниченное количество клиентов ...

public class EServer implements Runnable {
    private ServerSocket serverSocket;
    private int numberofConnections = 0;
    private Semaphore sem = new Semaphore(2);
    private volatile boolean keepProcessing = true;

    public EServer(int port)
            throws IOException {
        serverSocket = new ServerSocket(port);
    }

    @Override
    public void run() {
        while (keepProcessing) {
            try {
                sem.acquire();
                Socket socket = serverSocket.accept();
                process(socket, getNextConnectionNumber());
            } catch (Exception e) {
            } finally {
                sem.release();
            }
        }
        closeIgnoringException(serverSocket);
    }

    private synchronized int getNextConnectionNumber() {
        return ++numberofConnections;
    }

    // processing related methods
}

Ответы [ 5 ]

0 голосов
/ 10 января 2018

вам нужно удалить блок finally

0 голосов
/ 16 апреля 2010

Семафор не ограничивает количество подключений к серверу.

Семафор ограничивает количество потоков, обращающихся к определенной части кода. Следовательно, ваш сервер будет принимать столько входящих запросов сокетов, сколько сделано, , но каждый поток сокетов будет блокироваться на семафоре.

Кроме того, ваш метод run содержит цикл, который получает и освобождает семафор, что приводит к циклической обработке всех сокетов на семафоре.

Чтобы увидеть это в действии, добавьте несколько операторов журнала. Один до приобретения семафора, еще один сразу после его получения, другой перед выпуском и последний после его выпуска.

Так как ограничить количество подключений к серверу?

Проверьте параметр конструктора backlog в ServerSocket

public EServer (int port) 
        throws IOException 
{
    // 'backlog' is in fact a listening queue length. 
    // if more than 2 socket requests are made at a time,
    // they are refused. probably want to parameterize 
    // this :)
    serverSocket = new ServerSocket (port, 2); 
}
0 голосов
/ 16 апреля 2010

Как выглядит ваш process метод? Может ли он возвращаться раньше, чем вы хотите, и, следовательно, освободить семафор до того, как вы захотите?

0 голосов
/ 16 апреля 2010

Сколько тем вы создаете? Просто 1 экземпляр сервера в 1 потоке? Или 1 экземпляр используется в 2 потоках?

1 экземпляр / 1 поток - ваш цикл обрабатывается последовательно, обработка принимает 1 поток за один раз. Это не из-за семафора, а потому что это всего лишь один поток. Остальные соединения находятся в очереди в ожидании подтверждения.

1 экземпляр / 2 потока - ваш код (семафор) ограничивает ваш сервер до обработки приема 2 соединений одновременно, но TCP / IP позволяет принимать соединения в очередь (я думаю, общая длина очереди по умолчанию равна 5). Третий одновременный запрос (запрос, поступающий до завершения обработки любого из двух предыдущих запросов) будет ожидать определенное количество времени (я не помню, как долго клиенты ждут по умолчанию). Как и 4-й, 5-й и т. Д.

В любом случае : Таким образом, ваш код будет иметь неограниченные соединения, потому что код просто ограничивает количество принятых одновременно. После принятия соединения остаются, пока сервер или клиент не закроет соединение.

Обновлено - в ответ на комментарии OP, дающие дополнительную информацию.

процесс поддерживает постоянную связь с бесконечным циклом - Роберт 12 минут назад

0 голосов
/ 16 апреля 2010

Вы не должны вызывать release в вашем блоке finally. Наконец блоки всегда выполняются. Что вы хотите сделать, это снять блокировку в исключении, или когда ваш клиент отключается:

    while (keepProcessing) {
        try {
            sem.acquire();
            Socket socket = serverSocket.accept();
            process(socket, getNextConnectionNumber());
        } catch (Exception e) {
            //Here the client hasn't been connected, so release the lock.
            sem.release();
        } finally {
           //code here always executes, exception or not
        }
    }

Затем в соответствующем месте в коде вашего клиента снимите блокировку:

...
//The client is shutting down / disconnecting
serverInstance.sem.release(); //not good OOP

OR 

serverInstance.clientFinished(); //callback, where clientFinished in your server class will release the lock
...

Конечно, существуют разные способы снять блокировку в зависимости от того, как ваш код оформлен, но главное в том, что когда вы вызываете release в блоке finally, он всегда будет выполняться (делая разрешение доступным для следующего входящего соединения). Так что выпускайте его только a) на сервере, когда есть исключение (вы знаете, что соединение не было установлено) или b) на клиенте (возможно, через какой-то обратный вызов / прослушиватель на сервере), когда вы знаете, что соединение завершено / отключено / иным образом прекращено.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...