Java 在我的客户身上看不到OP_

Java 在我的客户身上看不到OP_,java,client,selector,nio,nio2,Java,Client,Selector,Nio,Nio2,我是NIO和NIO2的新手。我一直在玩Echo服务器示例代码,它可以完美地工作。我开始写一个类似的客户。我的目标是在一个主线程上运行多个客户端套接字连接 我确实获得了OP_CONNECT,然后选择器不返回并从以下位置超时: 而(选择器。选择(10000)>0){ .... } 如果忽略选择器并开始使用socketChannel.read(…)读取数据,则可以读取数据。所以,数据已经准备好读取了,但是我没有得到选择器。选择(10000)返回一些键 以下是完整的源代码,我非常感谢您的帮助: pack

我是NIO和NIO2的新手。我一直在玩Echo服务器示例代码,它可以完美地工作。我开始写一个类似的客户。我的目标是在一个主线程上运行多个客户端套接字连接

我确实获得了OP_CONNECT,然后选择器不返回并从以下位置超时: 而(选择器。选择(10000)>0){ .... }

如果忽略选择器并开始使用socketChannel.read(…)读取数据,则可以读取数据。所以,数据已经准备好读取了,但是我没有得到选择器。选择(10000)返回一些键

以下是完整的源代码,我非常感谢您的帮助:

package com.maker.webscraping.nio;

import java.io.IOException;
import java.net.StandardSocketOptions;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
import java.nio.charset.Charset;
import java.nio.charset.CharsetDecoder;
import java.util.Iterator;
import java.util.Map;
import java.util.Random;
import java.util.concurrent.ConcurrentHashMap;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;


public class EchoClient2 {
    private static final Logger logger = LoggerFactory.getLogger(EchoClient2.class);
    private static final Map<SocketChannel, EchoClient2> mapClients = new ConcurrentHashMap<>();

    private static final int DEFAULT_PORT = 5555;
    private static final String IP = "127.0.0.1";

    private final int clientID;
    private final ByteBuffer buffer;
    private final SocketChannel socketChannel;
    private final CharsetDecoder decoder;

    public int getClientID() {
        return clientID;
    }

    public ByteBuffer getBuffer() {
        return buffer;
    }

    public CharsetDecoder getDecoder() {
        return decoder;
    }

    //private static Selector selector = null;
    public static void main(String[] args) {
        Selector selector = null;
        try {
            selector = Selector.open();
            if (!selector.isOpen()) 
                throw new RuntimeException("Selector closed!");

            EchoClient2[] clients = new EchoClient2[2];

            clients[0] = new EchoClient2(0, selector);

            // wait for incomming events
            while (selector.select(10000)>0) {
                Iterator<SelectionKey> keys = selector.selectedKeys().iterator();
                while (keys.hasNext()) {
                    SelectionKey key = (SelectionKey) keys.next();

                    try (SocketChannel socketChannel = (SocketChannel) key.channel()) {

                        if (key.isConnectable()) {
                            // connected
                            logger.info("Client:{} connected!", clients[0].getClientID());
                            key.interestOps(SelectionKey.OP_READ); // <-- desprete tries
                            socketChannel.register(selector, SelectionKey.OP_READ | SelectionKey.OP_WRITE); // <-- desprete tries
                            logger.info("R:{}, W:{}, C:{}, validOps:{}", SelectionKey.OP_READ, SelectionKey.OP_WRITE, SelectionKey.OP_CONNECT,  socketChannel.validOps());
                            // close pending connections
                            if (socketChannel.isConnectionPending()) {
                                socketChannel.finishConnect();
                            }

                            read(key,selector); // <-- desprete tries
                            if (key.isReadable()) {
                                read(key,selector);
                            }// else if (key.isWritable()) {
                            //  this.writeOP(key);
                            //}

                        }
                    } catch (IOException e) {
                        logger.error("SocketChannel Exception!", e);
                    }
                }
            }
        } catch (IOException e) {
            logger.error("Selector IOException!", e);
        } finally {
            try {
                selector.close();
            } catch (IOException e) {}
        }       
    }

    public EchoClient2(int clientID, Selector selector) throws IOException {
        this.clientID = clientID;
        buffer = ByteBuffer.allocateDirect(2 * 1024);

        Charset charset = Charset.defaultCharset();
        decoder = charset.newDecoder();
//      if (selector==null)
//          selector = Selector.open();
        socketChannel = SocketChannel.open();
        if ((socketChannel.isOpen()) && (selector.isOpen())) {

            // configure non-blocking mode
            socketChannel.configureBlocking(false);
            // set some options
            socketChannel.setOption(StandardSocketOptions.SO_RCVBUF,
                    128 * 1024);
            socketChannel.setOption(StandardSocketOptions.SO_SNDBUF,
                    128 * 1024);
            socketChannel.setOption(StandardSocketOptions.SO_KEEPALIVE,
                    true);

            socketChannel.register(selector, SelectionKey.OP_CONNECT | SelectionKey.OP_READ | SelectionKey.OP_WRITE);
            //socketChannel.register(selector, SelectionKey.OP_CONNECT);

            // connect to remote host
            socketChannel.connect(new java.net.InetSocketAddress(IP, DEFAULT_PORT));

            // add it to the map
            mapClients.put(socketChannel, this);
        } else 
            throw new RuntimeException("Channel or Selector closed!");
    }

    // isReadable returned true
    private static int read(SelectionKey key, Selector selector) {

        try {
            SocketChannel socketChannel = (SocketChannel) key.channel();
            EchoClient2 client = mapClients.get(socketChannel);
            ByteBuffer buffer = client.getBuffer();

            buffer.clear();
            int numRead = -1;
            try {
                numRead = socketChannel.read(buffer);
            } catch (IOException e) {
                System.err.println("Cannot read error!");
            }

            if (numRead == -1) {
                mapClients.remove(socketChannel);
                System.out.println("Connection closed by: " + socketChannel.getRemoteAddress());
                socketChannel.close();
                key.cancel();
                return 1;
            }

            if (numRead == 0)
                throw new RuntimeException("numRead is 0!!!");

            buffer.flip();

            CharBuffer charBuffer = client.getDecoder().decode(buffer);
            System.out.println("server says:" + charBuffer.toString());

            if (buffer.hasRemaining()) {
                buffer.compact();
            } else {
                buffer.clear();
            }

            int r = new Random().nextInt(100);
            //if (r == 50) {
            //  System.out.println("50 was generated! Close the socket channel!");
            //  return 1;
            //} 

            ByteBuffer randomBuffer = ByteBuffer.wrap("Random number:".concat(String.valueOf(r))
                            .getBytes("UTF-8"));
            socketChannel.write(randomBuffer);
            key.interestOps(SelectionKey.OP_READ | SelectionKey.OP_WRITE);
            socketChannel.register(selector, SelectionKey.OP_READ | SelectionKey.OP_WRITE); // <-- desprete tries
        } catch (IOException e) {
            logger.error("IOException inside read!", e);

        } 
        return 0;
    }
}
package com.maker.webscraping.nio;
导入java.io.IOException;
导入java.net.StandardSocketOptions;
导入java.nio.ByteBuffer;
导入java.nio.CharBuffer;
导入java.nio.channels.SelectionKey;
导入java.nio.channels.Selector;
导入java.nio.channels.SocketChannel;
导入java.nio.charset.charset;
导入java.nio.charset.CharsetDecoder;
导入java.util.Iterator;
导入java.util.Map;
导入java.util.Random;
导入java.util.concurrent.ConcurrentHashMap;
导入org.slf4j.Logger;
导入org.slf4j.LoggerFactory;
公共类EchoClient2{
私有静态最终记录器Logger=LoggerFactory.getLogger(EchoClient2.class);
私有静态最终映射MapClient=new ConcurrentHashMap();
专用静态最终int默认_端口=5555;
私有静态最终字符串IP=“127.0.0.1”;
私人最终int客户ID;
专用最终字节缓冲区;
私人最终SocketChannel SocketChannel;
专用最终字符集解码器;
public int getClientID(){
返回客户ID;
}
public ByteBuffer getBuffer(){
返回缓冲区;
}
公共字符集解码器getDecoder(){
返回解码器;
}
//私有静态选择器=null;
公共静态void main(字符串[]args){
选择器=null;
试一试{
选择器=selector.open();
如果(!selector.isOpen())
抛出新的RuntimeException(“选择器关闭!”);
EchoClient2[]客户端=新的EchoClient2[2];
客户端[0]=新的EchoClient2(0,选择器);
//等待输入事件
而(选择器。选择(10000)>0){
迭代器键=选择器。selectedKeys()。迭代器();
while(keys.hasNext()){
SelectionKey=(SelectionKey)keys.next();
try(SocketChannel SocketChannel=(SocketChannel)key.channel(){
if(key.isConnectable()){
//连接的
info(“客户端:{}已连接!”,客户端[0].getClientID();
key.interesttops(SelectionKey.OP_READ);//
此代码已经错误。它将在第一次出现选择超时时停止选择。它应该是:

while (selector.isOpen())
{
    if (selector.select(10000) > 0)
    {
        // ...
    }
}
还有其他问题

  • 只有当
    finishConnect()
    返回
    true时,才应假定连接已完成。
  • 连接完成时读取无效。您应该仅在
    key.isReadable()
    为true时读取。您需要单独进行测试,而不是将一个测试附加到
    isConnectable()
    案例中
  • 类似地,
    iswriteable()也需要单独的大小写。
  • 除非您有要写的内容,否则不应注册
    OP_WRITE
    ,最好是在您尝试写入内容时获得零长度返回后注册。
    OP_WRITE
    表示套接字发送缓冲区未满。这几乎总是正确的
  • 您需要在
    键之后调用
    键。remove()
    。next(),
    否则您将一次又一次地获得相同的选定键。选择器不会清除选定的键集
  • 您的评论
    //关闭挂起的连接
    完全不正确
  • 下面的
    isConnectionPending()
    调用是多余的。它当然是挂起的,这就是为什么您得到了
    OP\u CONNECT。

  • 非常感谢您的帮助和所有这些评论。我的意图是在选择器超时时停止,因为我在客户端,对吗?是的,1)是正确的。2)是的,正如您所看到的,我用“Disprete Trys”注释了代码就在它下面,我正在检查是否可读取,但我从未收到任何通知。3,4)是的,你也在这里,我试图查看我是否收到任何通知,但我没有!5)是的,你完全正确,我不确定我是如何错误地错过了这一次,我认为finishConnect()只有在建立连接后才会返回谢谢,我会根据您的建议更改代码,希望我能开始看到一些notifications@BehzadRe(2)为什么套接字在连接时会神奇地变得可读?它不会,除非服务器已经发送了一些数据。通常,服务器会等待您发送请求,然后发送回复。是的,在很多情况下,您是对的,并不总是这样。在我的情况下,我拥有的测试服务器会发送一个“你好”在OP_接受后立即。我已经按照您的建议修复了代码。谢谢,
    while (selector.isOpen())
    {
        if (selector.select(10000) > 0)
        {
            // ...
        }
    }