Как прекратить поток, который был заблокирован слишком долго из-за Socket.accept ()? - PullRequest
1 голос
/ 03 апреля 2020
public class Slave implements Runnable {
   public ServerSocket slaveSocket;

   public Slave(ServerSocket sk) {socket = sk;}

   @Override
   public void run() {
      Socket client = slaveSocket.accept(); // slave will wait to serve a client
      // more code...

      Socket clientPart2 = slaveSocket.accept();
      // more code...
   }
}

public class Server {
   public static void main(String[] args) {
       // for example only, incomplete code
       ServerSocket serverSocket = new ServerSocket(0); // a client connect to 8088
       Slave slave = new Slave(serverSocket);
       new Thread(slave).start(); // slave serve the current client, the server wait for new client

       // send new slave's port to client ... 
   }
}

Итак, у меня есть сервер, который обслуживает несколько клиентов одновременно. Каждый раз, когда клиент подключается, сервер создает нового ведомого, отправляет IP / порт этого ведомого клиенту, а затем клиент будет работать с ведомым.

Однако, если клиент получит адрес ведомого, то ничего не делать (или выйти) ( Edit: это означает, что клиент и сервер подключены, но клиент ничего не делает, например, если пользователь идет на обед) slaveSocket.accept() заставляет этот подчиненный поток работать вечно, что расточительно

Я хочу, чтобы подчиненная нить вышла через 30 секунд ожидания slaveSocket.accept(). Поскольку slaveSocket.accept() блокирует, я не могу сделать это изнутри void run().

Как правильно и чисто решить эту проблему? Спасибо.

Редактировать 1: ServerSocket передается ведомому, потому что клиент может иметь несколько процессов, которые будут подключаться к этому ведомому. Так что он не просто выполняет одну функцию.

Ответы [ 2 ]

3 голосов
/ 03 апреля 2020

Если вы установили тайм-аут с помощью setSoTimeout, а клиент не подключился, ServerSocket.accept сгенерирует исключение. Вы можете поймать это исключение.

Чтобы установить время ожидания 30 секунд, используйте:

serverSocket.setSoTimeout(30000)
2 голосов
/ 03 апреля 2020

Неблокирующий ввод / вывод:

Взгляните на AsynchronousServerSocketChannel метод accept , который возвращает Future. Затем Future имеет геттер с тайм-аутом , который может выполнить то, что вы просите.

Примечание: вы можете прочитать учебное пособие .

Затем получатель вернет AsynchronousSocketChannel, который может быть преобразован обратно в блокировку с помощью соответствующих методов Channels.newInputStream и Channels.newOutputStream, которые будут использоваться с подход блокировки в рабочих потоках.

Блокировка ввода-вывода:

Я думаю, что вы на самом деле имели в виду, как реализовать сервер, который принимает клиентов последовательно и обслуживает их параллельно, с блокировкой ввода-вывода. О. Если это так, то вы можете взглянуть на следующий пример:

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Objects;

public class Main {

    public static class Worker implements Runnable {
        private final Socket sck;
        private OutputStream os;
        private InputStream is;

        public Worker(final Socket sck) {
            this.sck = Objects.requireNonNull(sck);
        }

        @Override
        public void run() {
            try {
                os = sck.getOutputStream();
                is = sck.getInputStream();

                //ALL the work with the client goes here, unless you need more than one connections with him.
            }
            catch (final IOException iox) {
                System.err.println(iox);
            }
            finally {
                try { is.close(); } catch (final IOException | RuntimeException x) {}
                try { os.close(); } catch (final IOException | RuntimeException x) {}
                try { sck.close(); } catch (final IOException | RuntimeException x) {}
            }
        }
    }

    public static void main(final String[] args) {
        ServerSocket srv = null;
        try {
            srv = new ServerSocket(8088);
            while (true)
                new Thread(new Worker(srv.accept())).start();
        }
        catch (final IOException iox) {
            System.err.println(iox);
        }
        finally {
            try { srv.close(); } catch (final IOException | RuntimeException x) {}
        }
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...