Java - 使用nio的ReadObject

cor*_*iKa 5 java serialization nio

在传统的阻塞线程服务器中,我会做这样的事情

class ServerSideThread {

    ObjectInputStream in;
    ObjectOutputStream out;
    Engine engine;

    public ServerSideThread(Socket socket, Engine engine) {
        in = new ObjectInputStream(socket.getInputStream());
        out = new ObjectOutputStream(socket.getOutputStream());
        this.engine = engine;
    }

    public void sendMessage(Message m) {
        out.writeObject(m);
    }

    public void run() {
        while(true) {
            Message m = (Message)in.readObject();
            engine.queueMessage(m,this); // give the engine a message with this as a callback
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

现在,可以预期该对象非常大.在我的nio循环中,我不能简单地等待对象通过,所有其他连接(具有更小的工作负载)将等待我.

在告诉我的nio频道之前,我怎么才能通知连接有整个对象?

Pet*_*rey 7

您可以将对象写入ByteArrayOutputStream,从而允许您在发送对象之前给出长度.在接收方,在尝试解码之前读取所需的数据量.

但是,您可能会发现使用Object*Stream阻塞IO(而不是NIO)更简单,更有效


编辑这样的东西

public static void send(SocketChannel socket,  Serializable serializable) throws IOException {
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    for(int i=0;i<4;i++) baos.write(0);
    ObjectOutputStream oos = new ObjectOutputStream(baos);
    oos.writeObject(serializable);
    oos.close();
    final ByteBuffer wrap = ByteBuffer.wrap(baos.toByteArray());
    wrap.putInt(0, baos.size()-4);
    socket.write(wrap);
}

private final ByteBuffer lengthByteBuffer = ByteBuffer.wrap(new byte[4]);
private ByteBuffer dataByteBuffer = null;
private boolean readLength = true;

public Serializable recv(SocketChannel socket) throws IOException, ClassNotFoundException {
    if (readLength) {
        socket.read(lengthByteBuffer);
        if (lengthByteBuffer.remaining() == 0) {
            readLength = false;
            dataByteBuffer = ByteBuffer.allocate(lengthByteBuffer.getInt(0));
            lengthByteBuffer.clear();
        }
    } else {
        socket.read(dataByteBuffer);
        if (dataByteBuffer.remaining() == 0) {
            ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(dataByteBuffer.array()));
            final Serializable ret = (Serializable) ois.readObject();
            // clean up
            dataByteBuffer = null;
            readLength = true;
            return ret;
        }
    }
    return null;
}
Run Code Online (Sandbox Code Playgroud)

  • @glowcoder,使用NIO,执行读取,它会告诉您读取了多少字节.然后取出这些字节,并将它们放在为每个连接维护的单独缓冲区中,直到累积了所需的字节数.我建议在您自己的输入和输出流对中包装此功能. (2认同)