Как сделать функцию accept () неблокируемой? - PullRequest
0 голосов
/ 15 апреля 2019

Мой сервер прослушивает 2 порта, и он должен выполнять отдельные функции на каждом порту одновременно.

Моя проблема в том, что сервер блокируется, пока клиент первого порта не будет подключен первым.
Например: если второй клиент попытался подключиться ко 2-му порту до того, как клиент подключится к 1-му порту, он не позволит ему соединиться.

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

public static void main(String[] args) throws Exception {

        System.out.println("server is running.");
        int clientNumber = 0;
        ServerSocket listenerTrans = new ServerSocket(9899);
        ServerSocket listenerDeter = new ServerSocket(9898);
        try {
            while (true) {


                new Deteriment(listenerDeter.accept(), clientNumber++).start();
                new Transpose(listenerTrans.accept(), clientNumber++).start();
            }

        } finally {
            listenerTrans.close();
            listenerDeter.close();
        }
    }

Deteriment и Transpose - мои классы, которые расширяются до класса потока.

Я хочу, чтобы listenerDeter.accept ()чтобы не блокировать listenerTrans.accept (), я хочу, чтобы оба потока accept () происходили параллельно.Кроме того, почему это не происходит параллельно в моем коде?

Ответы [ 2 ]

1 голос
/ 16 апреля 2019

Ответ - использовать ServerSocketChannel и Selector. Selector позволяет вашему приложению мультиплексировать ввод / вывод на нескольких каналах, используя один поток. Может использоваться в режиме синхронизации или неблокирования

Вот пример (заимствовано из Как работает java nio ServerSocketChannel accept? и адаптировано для вашего варианта использования):

// Create the 2 server socket channels
ServerSocketChannel server1 = ServerSocketChannel.open();
ServerSocketChannel server2 = ServerSocketChannel.open();
// Configure channels for nonblocking I/O
server1.configureBlocking(false);
server2.configureBlocking(false);
// Bind channels' IP and port
server1.socket().bind(new java.net.InetSocketAddress(host, 9899));
server2.socket().bind(new java.net.InetSocketAddress(host, 9898));
// Create the selector
Selector selector = Selector.open();
// Register channels to selector (type OP_ACCEPT)
SelectionKey key1 = server1.register(selector, SelectionKey.OP_ACCEPT);
SelectionKey key2 = server2.register(selector, SelectionKey.OP_ACCEPT);

while (true) {
    selector.select(); // blocks until one or more of the registered channels 
                       // has actionable I/O
    Iterator it = selector.selectedKeys().iterator();
    while (it.hasNext()) {
        SelectionKey selKey = (SelectionKey) it.next();
        if (selKey.isAcceptable()) {
            ServerSocketChannel ssc = (ServerSocketChannel) selKey.channel();
            SocketChannel sc = ssc.accept();
            if (selKey.equals(key1)) {
                new Deteriment(sc.socket() ...).start();
            } else {
                new Transpose(sc.socket(), ...).start();
            }
        }
    }
}

(Предупреждения: 1: не проверено, 2: может быть более элегантно, 3: возможна утечка ресурсов, 4: вам действительно следует использовать пул / исполнитель потоков, а не запускать новые потоки вручную)

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

Итак, прежде всего, если вы хотите, чтобы он был асинхронным, вам нужно использовать отдельный поток для каждого ServerSocket, который вы объявляете.Зачем?По замыслу java.net блокировал немасштабируемый способ работы с сетевыми мыслями.Если вы хотите, чтобы он был неблокирующим, более масштабируемым, но менее абстрагированным (я имею в виду, что вы будете размещать буферы ^ ^), вам следует искать java nio.** РЕДАКТИРОВАТЬ: ** Я немного модифицирую твой код, он должен сделать работу, но его невозможно улучшить, я имею в виду, что это не самая элегантная версия ^ ^

public static void main(String[] args) throws Exception {
    System.out.println("server is running.");
    final int[] clientNumber = {0};
    ServerSocket listenerTrans = new ServerSocket(9899);
    ServerSocket listenerDeter = new ServerSocket(9898);
    try {
        ExecutorService ex = Executors
            .newFixedThreadPool(2);
            ex.execute(
                () -> {
                    try {
                        Socket s = listenerDeter.accept();
                        new Deteriment(s, clientNumber[0]++).start();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            );
            ex.execute(
                () -> {
                    try {
                        Socket s = listenerDeter.accept();
                        new Transpose(s, clientNumber[0]++).start();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            );
    } finally {
        //listenerTrans.close();
        //listenerDeter.close();
    }
}  
...