Java NIO SeletionKey迭代器和密钥处理,我做得对吗?
我正在关注JavaNIO。我找到了正确的java文件。我已经将代码调整为在单个端口而不是多个端口上操作,并将数据简单地输出到屏幕上,而不是将其回显到客户端 当我运行代码时,无论是我的版本还是上面超链接上的版本,都显示通道处理不当。我只是从我笔记本电脑风扇的声音中得出这个结论,在放置了几条快速的Java NIO SeletionKey迭代器和密钥处理,我做得对吗?,java,multithreading,sockets,nio,Java,Multithreading,Sockets,Nio,我正在关注JavaNIO。我找到了正确的java文件。我已经将代码调整为在单个端口而不是多个端口上操作,并将数据简单地输出到屏幕上,而不是将其回显到客户端 当我运行代码时,无论是我的版本还是上面超链接上的版本,都显示通道处理不当。我只是从我笔记本电脑风扇的声音中得出这个结论,在放置了几条快速的System.out.println()消息后,我设法缩小了问题的范围。起初我认为selector.select()方法由于某种原因没有阻塞,通道看起来是空的,但是while(hascantent)循环一直
System.out.println()
消息后,我设法缩小了问题的范围。起初我认为selector.select()
方法由于某种原因没有阻塞,通道看起来是空的,但是while(hascantent)
循环一直在迭代
经过一番搜索,我发现可能是我没有正确地操作钥匙。当从通道读取数据后,我调整代码以取消while(iterator.hasNext())循环底部if语句中的SelectionKey
这似乎已经达到了目的,现在我收到一条消息,通知在通道关闭之前没有更多的字节可读取,总体上运行起来似乎更平稳
这是我到目前为止所做工作的代码,我对如何实现这一点的想法正确吗?我是否在正确的位置取消了钥匙
public class ServerRunnable implements Runnable {
private int serverPort;
private int queueLength;
public ServerRunnable(int serverPort, int queueLength) {
this.serverPort = serverPort;
this.queueLength = queueLength;
}
private boolean running;
private ServerSocketChannel serverSocketChannel;
private ByteBuffer buffer = ByteBuffer.allocate(1024);
@Override
public void run() {
try {
Selector selector = Selector.open();
serverSocketChannel = ServerSocketChannel.open();
serverSocketChannel.configureBlocking(false);
ServerSocket serverSocket = serverSocketChannel.socket();
serverSocket.bind(new InetSocketAddress(serverPort));
System.out
.println("DeviceServerV0.2 - Going to Listen for connections on port: "
+ serverSocket.getLocalPort());
running = true;
SelectionKey serverAcceptKey = serverSocketChannel.register(
selector, SelectionKey.OP_ACCEPT);
int count = 0;
while (running) {
int keyCount = selector.select();
System.out.println("keyCount: " + keyCount);
Set<SelectionKey> selectedKeys = selector.selectedKeys();
Iterator keyIterator = selectedKeys.iterator();
while (keyIterator.hasNext()) {
SelectionKey key = (SelectionKey) keyIterator.next();
if ((key.readyOps() & SelectionKey.OP_ACCEPT) == SelectionKey.OP_ACCEPT) {
ServerSocketChannel ssc = (ServerSocketChannel) key
.channel();
SocketChannel sc = ssc.accept();
sc.configureBlocking(false);
// Here we add the new connection to the selector
SelectionKey newKey = sc.register(selector,
SelectionKey.OP_READ);
keyIterator.remove();
} else if ((key.readyOps() & SelectionKey.OP_READ) == SelectionKey.OP_READ) {
SocketChannel sc = (SocketChannel) key.channel();
// Going with this from the tutorial for now.
// TODO: Implement proper boolean controls here
while (true) {
buffer.clear();
int read = sc.read(buffer);
if (read <= 0) {
// System.out.println("Bytes read: " + read);
System.out
.println("No more bytes, breaking loop.");
break;
} else {
buffer.flip();
String result = new String(buffer.array());
System.out
.println("Buffer Contents: " + result);
}
}
keyIterator.remove();
key.cancel();
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
public类ServerRunnable实现Runnable{
专用int服务器端口;
私有整数队列长度;
public ServerRunnable(int serverPort,int queueLength){
this.serverPort=serverPort;
this.queueLength=队列长度;
}
私有布尔运行;
专用服务器socketchannel服务器socketchannel;
私有ByteBuffer缓冲区=ByteBuffer.allocate(1024);
@凌驾
公开募捐{
试一试{
选择器=选择器。打开();
serverSocketChannel=serverSocketChannel.open();
serverSocketChannel.configureBlocking(false);
ServerSocket ServerSocket=serverSocketChannel.socket();
bind(新的InetSocketAddress(serverPort));
系统输出
.println(“DeviceServerV0.2-将侦听端口上的连接:”
+serverSocket.getLocalPort());
运行=真;
SelectionKey serverAcceptKey=serverSocketChannel.register(
选择器,SelectionKey.OP_ACCEPT);
整数计数=0;
(跑步时){
int keyCount=selector.select();
System.out.println(“keyCount:+keyCount”);
设置selectedKeys=选择器。selectedKeys();
迭代器keyIterator=selectedKeys.Iterator();
while(keyIterator.hasNext()){
SelectionKey=(SelectionKey)keyIterator.next();
if((key.readyOps()&SelectionKey.OP_ACCEPT)==SelectionKey.OP_ACCEPT){
ServerSocketChannel ssc=(ServerSocketChannel)键
.channel();
SocketChannel sc=ssc.accept();
sc.configureBlocking(假);
//在这里,我们将新连接添加到选择器
SelectionKey newKey=sc.寄存器(选择器,
选择键。操作(读取);
keyterator.remove();
}else if((key.readyOps()&SelectionKey.OP\u READ)==SelectionKey.OP\u READ){
SocketChannel sc=(SocketChannel)key.channel();
//现在,请继续本教程中的内容。
//TODO:在此处实现适当的布尔控件
while(true){
buffer.clear();
int read=sc.read(缓冲区);
当频道的readyOps()
包含SelectionKey.OP\u read
时,如果(读取),则意味着某些数据可以读取,而不是说频道可以完全读取到其末端。但这是您在while(true)
循环中所做的;您正在读取并因此轮询频道,直到到达其末端为止
正确的处理方法是读取一次,不要尝试再次读取,除非下一个选择报告有更多数据要读取。好的,谢谢!我已取出while(true)
循环,并将键移动到if()中(阅读很棒!非常感谢你的帮助,我觉得我终于掌握了这一点。如果你不介意的话,最后一个问题是——当我阅读频道的数据时,我将密切关注“消息的结尾”标记,此时我需要响应。在收到该标记时立即响应是一种好的做法,还是应该设置写入操作的位,让选择器决定何时处理写入操作。请记住,最终我希望此系统使用线程池进行处理。我甚至不确定是否询问ri这里有一个问题,很抱歉,如果是在第一次写入通道时,缓冲区应该是空的,因此您可以简单地启动写入。但是,将第一次写入与所有其他写入一样处理,也就是说,等待通道准备好写入,让一段代码唯一地处理所有写入操作离子。谢谢你!你帮了我很大的忙,我现在对这一点有了更好的理解。它确实会带来伤害。它会增加开销。或者你必须一直注册OP_写入,这会导致大部分时间占用CPU,或者你必须注册OP_写入并等待下一次选择迭代,直到你可以写入为止,这会增加延迟。不管是哪种方式它的开销太大,而且完全没有必要。正确的方法是编写