简体   繁体   English

Java NIO2并发完成处理程序

[英]Java NIO2 concurrent completion handlers

I am writing NIO2 server, and I need to make asynchronous read operations on an AsynchronousSocketChannel, each of these operations consists of reading an integer, and further reading from the same channel number of bytes equal to this integer. 我正在编写NIO2服务器,我需要在AsynchronousSocketChannel上进行异步读取操作,这些操作中的每一个都包括读取一个整数,并进一步从等于该整数的相同通道字节数中读取。 Problem is, when I put two or more CompletionHandler's on channel in a row (cause there are requests for multiple reading operations), and first of these handlers gets fired, my further reading code in complete() method of the first handler cant work properly, because second handler gets fired instantly when there's info on channel. 问题是,当我在通道上连续放置两个或多个CompletionHandler时(因为有多次读取操作的请求),并且首先触发了这些处理程序,我在第一个处理程序的complete()方法中进一步读取的代码无法正常工作,因为当频道上有信息时,第二个处理程序立即被解雇。 How can I block channel 'til further reading complete() completes without Future thing? 在没有Future的情况下,如何阻止通道'直到进一步阅读complete()完成? I cant use Future cause I need to put handler to the socket and then pass to the other tasks. 我不能使用Future原因,因为我需要将处理程序放入套接字,然后传递给其他任务。

for (final Map.Entry<String, AsynchronousSocketChannel> entry : ipSocketTable.entrySet()) {
        try {
            final AsynchronousSocketChannel outSocket = entry.getValue();
            synchronized (outSocket) {
                final ByteBuffer buf = ByteBuffer.allocateDirect(9);
                outSocket.read(buf, null, new DataServerResponseHandler(buf, outSocket, resultTable, server, entry.getKey()));
            }

        } catch (Exception e) {

        }
    }

Here is DataServerResponseHandler class: 这是DataServerResponseHandler类:

class DataServerResponseHandler implements CompletionHandler<Integer, Void> {

    private ConcurrentHashMap<String, Boolean> resultTable = null;
    private AsynchronousSocketChannel channel = null;
    private TcpServer server;
    private String ip;
    private ByteBuffer msg;

    public DataServerResponseHandler(ByteBuffer msg, AsynchronousSocketChannel channel,
            ConcurrentHashMap<String, Boolean> resultTable, TcpServer server, String ip) {
        this.msg = msg;
        this.channel = channel;
        this.resultTable = resultTable;
        this.server = server;
        this.ip = ip;
    }

    @Override
    public void completed(Integer result, Void attachment) {
            try {
                msg.rewind();
                int resultCode = msg.get() & 0xff;
                int ipOne = msg.get() & 0xff;
                int ipTwo = msg.get() & 0xff;
                int ipThree = msg.get() & 0xff;
                int ipFour = msg.get() & 0xff;
                int length = msg.getInt();
                msg.rewind();
                ByteBuffer buf = ByteBuffer.allocateDirect(length);
                channel.read(buf).get();
                buf.rewind();
            } catch (Exception e) {
                e.printStackTrace();
            }

        }

    @Override
    public void failed(Throwable exc, Void attachment) {
        throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
    }

}

This code has several problems. 这段代码有几个问题。
First read doesn't guarantee that it will read all remaining bytes but calls completion handler as soon as it reads at least one byte. 首次读取并不能保证它将读取所有剩余字节,但会在读取至少一个字节后立即调用完成处理程序。 Therefore you have to check position of buffer and re-invoke the read until you have 9 bytes for header or length for the payload. 因此,您必须检查缓冲区的位置并重新调用读取,直到头有9个字节或有效负载长度为止。

if (msg.position() < 9) {
    channel.read(msg, null, this);
    return;
}

For the second part in order to continue asynchronous approach again run the read with completion handler. 对于第二部分,为了继续异步方法,请再次运行带有完成处理程序的读取。 You can create new one which would specifically handle the payload or reuse the existing one and you'll have to remember the state: 您可以创建一个专门用于处理有效负载或重用现有负载的新负载,并且必须记住状态:

switch (state) {
case READ_HEADER:
    if (msg.remaining() > 0) {
        channel.read(msg, null, this);
        return;
    }
    // do the parsing the IP and length
    state = READ_PAYLOAD;
    channel.read(payloadBuf, null, this);
    break;

case READ_PAYLOAD:
    if (payloadBuf.remaining() > 0) {
        channel.read(payloadBuf, null, this);
        return;
    }
    payloadBuf.flip();
    // get content from payloadBuf
    break;
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM