Java: Возможно ли одновременное чтение и запись в блокирующем SocketChannel через Object (In | Out) putStreams? - PullRequest
8 голосов
/ 06 октября 2008

Я создал ObjectInputSteam и ObjectOutputStream для блокировки SocketChannel и пытаюсь читать и писать одновременно. Мой код примерно такой:

socketChannel = SocketChannel.open(destNode);
objectOutputStream = new ObjectOutputStream(Channels.newOutputStream(socketChannel));
objectInputStream = new ObjectInputStream(Channels.newInputStream(socketChannel));

Thread replyThread = new Thread("SendRunnable-ReplyThread") {
    @Override
    public void run() {
        try {
            byte reply = objectInputStream.readByte();//(A)
            //..process reply
        } catch (Throwable e) {
            logger.warn("Problem reading receive reply.", e);
        }
    }
};
replyThread.start();

objectOutputStream.writeObject(someObject);//(B)
//..more writing

Проблема заключается в блоках записи в строке (B) до тех пор, пока не завершится чтение в строке (A) (блоки в объекте, возвращенные SelectableChannel#blockingLock()). Но логика приложения диктует, что чтение не будет завершено, пока не завершатся все записи, поэтому у нас есть эффективная тупиковая ситуация.

SocketChannel Javadocs говорит, что одновременное чтение и запись поддерживаются.

У меня не было такой проблемы, когда я пробовал обычное решение Socket:

Socket socket = new Socket();
socket.connect(destNode);
final OutputStream outputStream = socket.getOutputStream();
objectOutputStream = new ObjectOutputStream(outputStream);
objectInputStream = new ObjectInputStream(socket.getInputStream());

Однако тогда я не смогу воспользоваться преимуществами производительности FileChannel#transferTo(...)

Ответы [ 4 ]

4 голосов
/ 13 февраля 2009

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

public InputStream getInputStream() throws IOException {
    return Channels.newInputStream(new ReadableByteChannel() {
        public int read(ByteBuffer dst) throws IOException {
            return socketChannel.read(dst);
        }
        public void close() throws IOException {
            socketChannel.close();
        }
        public boolean isOpen() {
            return socketChannel.isOpen();
        }
    });
}

public OutputStream getOutputStream() throws IOException {
    return Channels.newOutputStream(socketChannel);
}
4 голосов
/ 07 октября 2008

Кажется, это ошибка в java.nio.channels.Channels (спасибо Тому Хоутину; опубликуйте его как ответ в следующий раз). Хорошее описание и обходные пути описаны здесь (на самом деле это дубликат ошибки, указанной Томом):

Я протестировал обходной путь, и он работает.

2 голосов
/ 06 октября 2008

Если вы хотите использовать InputStream и OutputStream одновременно с SocketChannel, при взгляде на источник вам кажется, что вам нужно вызвать SocketChannel.socket () и использовать потоки из того, что ведет себя немного по-другому.

0 голосов
/ 07 октября 2008

Интересная ошибка! Вы говорите, что вы не можете использовать FileChannel # TransferTo. Как насчет упаковки потоков ввода-вывода не-NIO-сокета в каналы с помощью Channesl # newChannel перед передачей в FileChannel # TransferTo?

...