我正在尝试将我的网络从标准IO转移到NIO,并按照几个教程来尝试解决这个问题,而我,我自己,我决定花掉我的一个好主意。第一周重写所有应用程序逻辑处理的核心,我从来没有想到我将无法建立基本的网络。
目前网络处于一个非常基本的阶段,一切都在一个循环中抛出,我不能老实说我已经做了任何尝试,使它看起来不错,考虑到我没有线索我正在实现的目标是先弄清楚如何做到这一点,然后再回过头来进行改造。
以下是我用来初始化服务器的代码:
// 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接口,在这个方法完成后直接启动一个新线程,在这个线程中我们包含以下代码:
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
来处理我们的连接和数据的原因..并且是所有基于NIO的网络运行的,你会看到我正在呼叫两种不同的方法使这不是一团糟,第一种是#handleConnection
,另一种是解码功能。
handle连接方法创建了我的Connection
类的新实例,并将其附加到SelectionKey,如下所示:
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
方法时,会调用该错误,如下所示:
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
尝试从网络读取时,似乎会调用该错误,更具体地说是在这行代码中:
byte[] bytes = ByteStreams.toByteArray(dataInputStream);
错误:
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完全不同,但学习是学习,呃?
编辑:我想我知道如何从客户端发送数据是有帮助的,它只是一个非常基本的测试应用程序来实现这一点:
socket = new Socket("127.0.0.1", 5055);
DataOutputStream dos = new DataOutputStream(socket.getOutputStream());
dos.writeBoolean(false);
答案 0 :(得分:0)
如果您在非阻塞中转移到NIO,则无法继续使用流。如果你想使用流,那么根本不使用NIO。我现在就停止迁移项目。