首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >从IO转向NIO - Networking、IllegalBlockingModeException

从IO转向NIO - Networking、IllegalBlockingModeException
EN

Stack Overflow用户
提问于 2014-11-29 07:07:47
回答 1查看 473关注 0票数 1

我正在尝试将我的网络从标准IO转移到NIO,并遵循几个教程试图弄清楚,而我,我自己和我决定花第一周重写所有应用程序逻辑处理的核心是一个很好的想法,我从来没有想过我将无法设置基本的网络。

目前这个网络还处于一个非常基础的阶段,所有的东西都被扔进了一个while循环中,老实说,我不能说我已经尝试过让它看起来更漂亮,考虑到我不知道我在做什么,我的目标是先弄清楚如何做,然后再回去给它做个改头换面。

下面是我用来初始化服务器的代码:

代码语言:javascript
复制
    // Initializes the TCP Server and all of its components.
private void initTcpServer(int port) {
    try {
        // Create a new selector
        Selector socketSelector = SelectorProvider.provider()
                .openSelector();

        // Create a new non-blocking server socket channel;
        this.serverSocketChannel = ServerSocketChannel.open();
        this.serverSocketChannel.configureBlocking(false);

        // Bind the server socket to the specified address and port
        this.serverSocketChannel.socket().bind(
                new InetSocketAddress("127.0.0.1", port));

        // Register the server socket channel, indicating an interest in
        // accepting new connections
        this.serverSocketChannel.register(socketSelector,
                SelectionKey.OP_ACCEPT);

        // Set the selector for the server instance.
        this.selector = socketSelector;

    } catch (IOException e) {
        e.printStackTrace();
    }
}

然后这个类实现了Runnable接口,在这个方法完成后会直接启动一个新的线程,在这个线程中我们包含以下代码:

代码语言:javascript
复制
public void run() {
    while (isRunning) {
        try {
            selector.selectNow();
        } catch (IOException io) {
            return;
        }

        Iterator<SelectionKey> it = selector.selectedKeys().iterator();

        while (it.hasNext()) {
            SelectionKey key = it.next();

            if (!key.isValid()) {
                it.remove();
                continue;
            }

            try {
                if (key.isAcceptable()) {
                    this.handleConnection(key);
                } else if (key.isReadable()) {
                    Connection connection = (Connection) key.attachment();
                    if (connection != null) {
                        try {
                            connection.getMasterProtocol()
                                    .decode(connection,
                                            connection.getInputStream());
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                }
            } finally {
                it.remove();
            }
        }
    }
}

据我所知,这是允许我们基于SelectionKey处理连接和数据的原因。你会看到我调用了两个不同的方法来使这个过程不那么混乱,第一个是#handleConnection,另一个是一个解码函数。

handle connection方法创建Connection类的一个新实例,并将其附加到SelectionKey,如下所示:

代码语言:javascript
复制
    public Connection(SelectionKey key) {
    try {
        // For an accept to be pending the channel must be a server socket channel.
        ServerSocketChannel serverSocketChannel = (ServerSocketChannel)key.channel();

        // Accept the connection and make it non-blocking.
        this.socketChannel = serverSocketChannel.accept();
        this.socketChannel.configureBlocking(false);

        // Set up other user data.
        this.inputStream = new DataInputStream(socketChannel.socket().getInputStream());
        this.masterProtocol = new MasterProtocol();

        // Register the new SocketChannel with our Selector, indicating
        // we'd like to be notified when there's data waiting to be read.
        key = this.socketChannel.register(OGServer.getInstance().getSelector(), SelectionKey.OP_READ);
        key.attach(this);

        // Add the current <SelectorKey, Connection> to the current connections collection.
        connections.put(key, this);

        Log.debug(getClass(), "Connection constructed successfully.");
    } catch(IOException e) {
        e.printStackTrace();
    }
}

当我尝试调用MasterProtocol#decode方法时,会调用该错误,如下所示:

代码语言:javascript
复制
public Object decode(Connection connection, DataInputStream dataInputStream) throws IOException {
    if(connection.getState() == ConnectionState.CONNECTED) {
        byte[] bytes = ByteStreams.toByteArray(dataInputStream);
        if(bytes.length < 4) {
            System.out.println("Not enough bytes read.");
            return null;
        }

        int bufferSize = dataInputStream.readInt();

        System.out.println("Buffer Size: " + bufferSize);

        while(bytes.length < bufferSize) {
            return null;
        }

        int test = dataInputStream.readInt();

        System.out.println("Test: " + test);

        return null;
    }
    return null;
}

该错误似乎是在DataInputStream尝试从网络读取时调用的,更具体地说,是在以下代码行中调用的:

代码语言:javascript
复制
byte[] bytes = ByteStreams.toByteArray(dataInputStream);

错误:

代码语言:javascript
复制
Exception in thread "Thread-0" java.nio.channels.IllegalBlockingModeException
at sun.nio.ch.SocketAdaptor$SocketInputStream.read(SocketAdaptor.java:190)
at sun.nio.ch.ChannelInputStream.read(ChannelInputStream.java:103)
at java.io.DataInputStream.read(DataInputStream.java:100)
at com.google.common.io.ByteStreams.copy(ByteStreams.java:70)
at com.google.common.io.ByteStreams.toByteArray(ByteStreams.java:115)
at net.ogserver.framework.net.protocol.MasterProtocol.decode(MasterProtocol.java:29)
at net.ogserver.framework.net.OGServer.run(OGServer.java:146)
at java.lang.Thread.run(Thread.java:745)

“IllegalBlockingModeException”异常让我感到困惑,因为我找到的所有信息都是关于设置非阻塞服务器的,但是DataInputStream实现是我自己的,所以我一定是做错了什么。NIO是一个与IO完全不同的世界,但学习就是学习,不是吗?

编辑:我想知道我是如何从客户端发送数据的会有所帮助,这只是一个非常基本的测试应用程序,它可以做到这一点:

代码语言:javascript
复制
        socket = new Socket("127.0.0.1", 5055);
        DataOutputStream dos = new DataOutputStream(socket.getOutputStream());
        dos.writeBoolean(false);
EN

回答 1

Stack Overflow用户

发布于 2014-11-29 10:18:52

如果你在非阻塞模式下转向NIO,你就不能一直使用流。如果你想使用streams,那么使用NIO根本没有什么好处。我现在就停止迁移项目。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/27196991

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档