我正在使用SocketChannel
并Selector
编写服务器。服务器的工作是允许客户端连接,从客户端读取消息并将消息写入客户端。
我在区分从客户端发送的消息和触发读取指令的其他数据时遇到了一些困难。
前任。当客户端连接时,我注意到执行了读取指令,而客户端没有发送任何数据。这很重要,因为服务器从客户端读取消息后,必须将该消息添加到消息队列中。这些消息将由外部应用程序从队列中删除和处理。问题是,每次读取触发时,这些 UFM(未识别消息)在尝试解码它们时都会破坏外部应用程序。
很抱歉,如果这个问题已经得到解答,我找不到完整的答案。
这是我的接受方法,如果我没记错的话,它会告诉选择器在数据可供读取时通知我们。
private void accept(SelectionKey key) throws IOException {
ServerSocketChannel serverSocketChannel = (ServerSocketChannel) key.channel();
// Accept the connection and make it non-blocking
SocketChannel socketChannel = serverSocketChannel.accept();
socketChannel.configureBlocking(false);
socketChannel.register(this.selector, SelectionKey.OP_READ);
}
这是等待事件的选择器方法。
while (should_run) {
try {
//Load all pending operations to key
while (!operations.isEmpty()) {
SelectionKey key = client.keyFor(getSelector());
if (!key.isValid()) {
operations.remove();
throw new Exception("Key not valid");
}
key.interestOps(operations.remove());
}
selector.select();
Iterator selectedKeys = selector.selectedKeys().iterator();
while (selectedKeys.hasNext()) {
SelectionKey key = (SelectionKey) selectedKeys.next();
//Check if key is valid
if (!key.isValid()) {
throw new Exception("Key not valid");
}
if (key.isAcceptable()) {
accept(key);
} else if (key.isReadable()) {
read(key);
} else if (key.isWritable()) {
write(key);
}
selectedKeys.remove();
}
} catch (Exception e) {
System.err.println("Something went wrong: " + e.getMessage());
e.printStackTrace();
}
}
这是读取函数,调用 ifkey.isReadable()
private void read(SelectionKey key) {
System.out.println("Read fired");
//Clear the buffer for new Data
this.readBuffer.clear();
int count;
try {
count = this.client.read(this.readBuffer);
if (count == -1) {
throw new IOException("Socket closed");
}
} catch (IOException e) {
key.cancel();
return;
}
//PROBLEM OCCURRING HERE
this.worker.give(this.readBuffer.array(), count);
}
读取者应该读取消息,并将消息传递给工作线程,在那里消息被解码并发生其他好事。
每次连接新客户端后都会调用 read 方法。计数通常很小,在 4 到 10 之间,当我使用 解码时 new String(data[], "UTF-8")
,结果是日语之类的..
count
我通过在每次调用 read 时简单地打印来测试这一点。
这个问题可以通过简单地检查每条传入消息的大小并忽略那些很小的消息来解决。但是,如果发生碎片化,这似乎会适得其反。
编辑:客户端示例代码:
Socket socket = new Socket("localhost", 3000);
ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());
while (true) {
String input = JOptionPane.showInputDialog("Send something to the server");
if (input == null)
break;
oos.writeObject(input);
}
注意:我没有对等方的源代码,但是这个非常简单的示例产生了完全相同的结果。在 MessageDialog 甚至提示向服务器发送消息之前,服务器已收到一条消息,该消息要么是日语,要么是一系列问号 (?? ???)。