Многопользовательский однопоточный NIO File Server?

Мой однопоточный сервер должен загружать архив подключившемся клиентам. Пока я могу передавать файл всего одному клиенту за раз, что меня не устраивает. Я ищу простой способ убрать блокировку или ещё как-то решить проблему (желательно без костылей).
P. S. сервер работает в отдельном потоке

class TCPServer implements Runnable {

    private InetSocketAddress address;
    private ServerSocketChannel serverSocketChannel;
    private Selector selector;
    private static FileChannel channel;

    TCPServer(String hostname, int port) throws IOException {
        address = new InetSocketAddress(hostname, port);
        serverSocketChannel = ServerSocketChannel.open();
        serverSocketChannel.configureBlocking(false);
        serverSocketChannel.socket().bind(address);
        selector = Selector.open();
        serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
    }

    @Override
    public void run() {
        while (!Thread.currentThread().isInterrupted()) {
            try {
                int select = 0;
                select = selector.select();
                if (select == 0)
                    continue;
                Iterator<SelectionKey> keys = selector.selectedKeys().iterator();
                while (keys.hasNext()) {
                    SelectionKey key = keys.next();
                    keys.remove();
                    if (!key.isValid())
                        continue;
                    if (key.isAcceptable())
                        accept(key);
                    if (key.isWritable())
                        write(key);
                }
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }
        closeConnections();
    }

    private void accept(SelectionKey key) throws IOException {
        var serverSocketChannel = (ServerSocketChannel) key.channel();
        var socketChannel = serverSocketChannel.accept();
        socketChannel.configureBlocking(false);
        socketChannel.register(selector, SelectionKey.OP_WRITE);
    }

    private void write(SelectionKey key) throws IOException {
        channel = FileChannel.open(Paths.get("/home/martin/file.zip"));
        var socketChannel = (SocketChannel) key.channel();
        var buffer = ByteBuffer.allocate(1024 * 4);

        while (channel.read(buffer) != -1) {
            buffer.flip();
            socketChannel.write(buffer);
            buffer.compact();
        } key.channel().close();
    }

    private void closeConnections() {
        try {
            selector.close();
            serverSocketChannel.socket().close();
            serverSocketChannel.close();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

}
  • Вопрос задан
  • 98 просмотров
Решения вопроса 1
sergey-gornostaev
@sergey-gornostaev Куратор тега Java
Седой и строгий
Цикл while в методе write останавливает цикл событий. Он не нужен. Да и в целом, так как никакой обработки файла вы не делаете, лучше использовать zero-copy метод transferTo.
Ответ написан
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы