9 Stimmen

Java: Sind gleichzeitige Lese- und Schreibvorgänge auf einem blockierenden SocketChannel über Object(In|Out)putStreams möglich?

Ich habe eine ObjectInputSteam y ObjectOutputStream bei einer Sperrung SocketChannel und ich versuche, gleichzeitig zu lesen und zu schreiben. Mein Code ist in etwa so:

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

Das Problem ist, dass das Schreiben in Zeile (B) blockiert wird, bis das Lesen in Zeile (A) abgeschlossen ist (blockiert das Objekt, das von SelectableChannel#blockingLock() ). Aber die Anwendungslogik schreibt vor, dass das Lesen nicht abgeschlossen wird, bevor alle Schreibvorgänge abgeschlossen sind, so dass wir eine effektive Blockade haben.

SocketChannel Die Javadocs besagen, dass gleichzeitiges Lesen und Schreiben unterstützt wird.

Ich hatte kein solches Problem, als ich eine normale Socket-Lösung ausprobierte:

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

Allerdings kann ich dann nicht die Leistungsvorteile nutzen, die die FileChannel#transferTo(...)

5voto

Kevin Wong Punkte 14146

Dies scheint ein Fehler zu sein in java.nio.channels.Channels (Dank an Tom Hawtin; beim nächsten Mal als Antwort einfügen). Eine gute Beschreibung und Abhilfe sind beschrieben aquí (eigentlich ein Duplikat des Fehlers, den Tom aufgelistet hat):

Ich habe die Umgehung getestet und sie funktioniert.

4voto

Nick Punkte 11419

Der Workaround im Fehlerbericht hat bei mir funktioniert. Es ist erwähnenswert, dass nur eine Wenn also die Leistung in einer Richtung besonders wichtig ist, können Sie die weniger wichtige Richtung umhüllen und sicher sein, dass die andere Richtung alle verfügbaren Optimierungen erhält.

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);
}

2voto

Tom Hawtin - tackline Punkte 142461

Wenn Sie InputStream und OutputStream gleichzeitig mit SocketChannel verwenden möchten, scheint es, dass Sie SocketChannel.socket() aufrufen und die Streams davon verwenden müssen, die sich etwas anders verhalten.

0voto

Alexander Punkte 8932

Interessanter Fehler! Sie sagen aber, dass Sie FileChannel#transferTo nicht verwenden können. Wie wäre es, wenn Sie die I/O-Streams des Nicht-NIO-Sockets mit Channesl#newChannel in Kanäle umwandeln, bevor Sie sie an FileChannel#transferTo übergeben?

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X