Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/visual-studio-code/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
从未选择多个操作代码的Java SocketChannel register()_Java_Selector_Nio_Socketchannel - Fatal编程技术网

从未选择多个操作代码的Java SocketChannel register()

从未选择多个操作代码的Java SocketChannel register(),java,selector,nio,socketchannel,Java,Selector,Nio,Socketchannel,我用Java构建了一个基于选择器的系统,可以接受多个客户端。它在OP_ACCEPT下注册了一个ServerSocketChannel,它接受()传入的连接并再次向选择器注册生成的SocketChannel。这是一点: ServerSocketChannel insock = ServerSocketChannel.open(); insock.configureBlocking(false); insock.socket().bind(new InetSocketAddress(

我用Java构建了一个基于选择器的系统,可以接受多个客户端。它在OP_ACCEPT下注册了一个ServerSocketChannel,它接受()传入的连接并再次向选择器注册生成的SocketChannel。这是一点:

ServerSocketChannel insock = ServerSocketChannel.open();
    insock.configureBlocking(false);
    insock.socket().bind(new InetSocketAddress(6789));

    Selector sel = Selector.open();
    SelectionKey joinchannel = insock.register(sel, SelectionKey.OP_ACCEPT);

    System.out.println("Ready to accept incoming connections.");

    while (true) {
        int ready = sel.selectNow();
        if (ready == 0)
            continue;
        Set<SelectionKey> selectedKeys = sel.selectedKeys();
        Iterator<SelectionKey> keyIterator = selectedKeys.iterator();
        while (keyIterator.hasNext()) {
            SelectionKey key = keyIterator.next();
            if(key.isAcceptable()){
                SocketChannel newConnection = insock.accept();
                System.out.println("New client "+newConnection+" connected.");
                newConnection.configureBlocking(false);
                newConnection.register(sel, SelectionKey.OP_READ).attach(new DGPlayer());
            }
else if(key.isReadable()){
                ByteBuffer buf = ByteBuffer.allocate(1024);
                int trans = ((SocketChannel)key.channel()).read(buf); buf.flip();
                byte[] ba = new byte[buf.remaining()]; buf.get(ba);
                String msg = new String(ba, 0, ba.length, Charset.forName("UTF-8"));

                if(trans > 0){
                    DGPlayer client = (DGPlayer) key.attachment();
                    System.out.println(client.name+": "+msg.trim());
                }
            }
                //              else if(key.isWritable()){
//                  ByteBuffer buf = ByteBuffer.allocate(48);
//                  buf.clear();
//                  buf.put(((String)key.attachment()).getBytes());
//                  buf.flip();
//                  
//                  SocketChannel target = ((SocketChannel)key.channel());
//                  while(buf.hasRemaining()) {
//                      target.write(buf);
//                  }
//                  
//                  key.attach(null);
//              }
但是,如果我为OP|u READ | OP|u WRITE注册SocketChannel,则什么也不会发生。据我所知,选择器从未找到可读()或可写()的通道。唯一的更改是为写入权限注册通道

知道为什么会这样吗

编辑-为了完成,这里有一些客户端代码:

while (true) {
        int readyChannels = sel.select();
        if (readyChannels == 0)
            continue;

        Set<SelectionKey> selectedKeys = sel.selectedKeys();
        Iterator<SelectionKey> keyIterator = selectedKeys.iterator();

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

            if (key.isReadable()) {
                ByteBuffer buf = ByteBuffer.allocate(1024);
                int trans = ((SocketChannel)key.channel()).read(buf); buf.flip();
                byte[] ba = new byte[buf.remaining()]; buf.get(ba);
                String msg = new String(ba, 0, ba.length, Charset.forName("UTF-8"));

                if(msg.trim().length() != 0)
                    System.out.println("Response from server: "+msg.trim());
            }
            else if(key.isWritable() && messages.size() > 0){
                String message = messages.remove();
                ByteBuffer buf = ByteBuffer.allocate(48);
                buf.clear();
                buf.put(message.getBytes(Charset.forName("UTF-8")));

                buf.flip();

                int written = outsock.write(buf);
                while(buf.hasRemaining()){
                    outsock.write(buf);
                }

                System.out.println("Wrote '"+message+"' to server");
            }
            keyIterator.remove();
        }
    }
while(true){
int readyChannels=sel.select();
如果(ReadyChannel==0)
继续;
设置selectedKeys=sel.selectedKeys();
迭代器keyIterator=selectedKeys.Iterator();
while(keyIterator.hasNext()){
SelectionKey=keyIterator.next();
if(key.isReadable()){
ByteBuffer buf=ByteBuffer.allocate(1024);
int trans=((SocketChannel)key.channel()).read(buf);buf.flip();
字节[]ba=新字节[buf.remaining()];buf.get(ba);
String msg=新字符串(ba,0,ba.length,Charset.forName(“UTF-8”));
如果(msg.trim().length()!=0)
System.out.println(“来自服务器的响应:+msg.trim());
}
else if(key.isWritable()&&messages.size()>0){
字符串消息=消息。删除();
ByteBuffer buf=ByteBuffer.allocate(48);
buf.clear();
buf.put(message.getBytes(Charset.forName(“UTF-8”));
buf.flip();
int WRITED=outsock.write(buf);
while(buf.haslaining()){
外储。写入(buf);
}
System.out.println(“向服务器写入“+”消息“+”);
}
keyterator.remove();
}
}

(客户端将服务器注册为OP|u READ | OP|u WRITE)

通常,如果您没有任何要主动写入的内容,那么为
OP|u WRITE
注册一个通道是个坏主意。大多数频道大部分时间都可以写入,因此每次调用
Selector.select
都会返回而不会阻塞并消耗资源。当您准备向频道写入内容时,最好将写入标志添加到,完成后删除该标志。

啊,好的。我希望这是显而易见的!我会在一秒钟内发布一些代码。即使是很明显的事情,当你问问题时发布代码也不会有任何伤害。当然。我已经发布了一些服务器代码。太冗长了,我不想把问题弄得乱七八糟。我会把客户代码放在附录或其他地方。您的客户代码中的
消息是什么?
阻塞队列
?它只是一个链接列表。这是我最新实现的一点,所以我不知道这是不是已经完成了。出于测试目的,列表已经包含要发送的内容。这在注册OP_READ时发送find。非常感谢,我现在根据需要改变我的兴趣。我想我现在终于掌握了选择器…@地铁公司更好的做法是,当你有东西要写时就写,当你遇到短写时才使用OP_write,即注册OP_write来重试写操作,并在重试成功后立即取消注册。编程稍微复杂一点,但可以节省延迟。@user207421“有东西要写时就写”,加上你(以前的EJP)的其他回答/评论(尖刻而乏味),让我更好地理解nio。。因此,我尊敬你。。不过我对名字的改变很好奇