1

我用来SocketChannel从客户端的服务器接收 TCP 流。例如:

Selector selector=Selector.open();
SocketChannel mychannel=SocketChannel.open(new InetSocketAddress(ip,port));
channel.configureBlocking(false);
SelectionKey channelkey=channel.register(selector,SelectionKey.OP_READ);

然后,我可以使用该selector.select()方法来处理阅读问题。

while(true){
    if(selector.select()!=0){
       Iterator<SelectionKey> it=selector.selectedKeys().iterator();
       while(it.hasNext()){
         SelectionKey key=it.next();
         it.remove();
         if(key.isReadable()){
            if(key.equals(channelkey)){

               //concrete handle
               ...
            }
         }
       }
    }
}

使用具体句柄,考虑到我想使用 InputStream(我想读取流线)从服务器端接收 tcp 流,有两种方法。一种是 using channel.socket(),另一种是使用 Channels。这里我使用channel.socket(),例如:

SocketChannel channel = (SocketChannel) key.channel();
key.cancel();
channel.configureBlocking(true);
InputStream ins = Channels.newInputStream(channel);
InputStreamReader is = new InputStreamReader(ins,"utf-8");
BufferedReader in = new BufferedReader(is);
String res = in.readLine();
while (!res.equals("")) {
    System.out.println(res);
    res = in.readLine();
}
       ......①

好的,现在我读完了一次tcp流。为了继续使用选择器,我应该将通道阻塞模式设置为false。

    channel.configureBlocking(false);

问题是,channel和selector组合的key被取消了,我想重新注册我的channel,怎么办?似乎如果我mychannel.register(selector, SelectionKey.OP_READ)在①上再次使用,它会抛出Exception.

我的 run() 方法代码如下:

try {
if (selector.select(getTimeout()) != 0) {
    Iterator<SelectionKey> it = selector.selectedKeys().iterator();
    while (it.hasNext()) {
        SelectionKey key = it.next();
        if (key.isReadable()) {
            SocketChannel channel = (SocketChannel) key.channel();
            key.cancel();
            channel.configureBlocking(true);
            InputStream ins = Channels.newInputStream(channel);
            InputStreamReader is = new InputStreamReader(ins,"utf-8");
            BufferedReader in = new BufferedReader(is);
            String res = in.readLine();
            while (!res.equals("")) {
                System.out.println("========" + res);
                res = in.readLine();
            }
            channel.configureBlocking(false);
            System.out.println(key.isValid());
            proxykey=channel.register(selector, SelectionKey.OP_READ);
        }
        it.remove();
    }
}
} catch (IOException ex) {
    ex.printStackTrace();
}

它抛出的异常是:

    Exception in thread "Thread-0" java.nio.channels.CancelledKeyException
at sun.nio.ch.SelectionKeyImpl.ensureValid(Unknown Source)
at sun.nio.ch.SelectionKeyImpl.interestOps(Unknown Source)
at java.nio.channels.spi.AbstractSelectableChannel.register(Unknown Source)
at java.nio.channels.SelectableChannel.register(Unknown Source)
at AgentThread.run(AgentThread.java:185)
4

1 回答 1

1

SelectionKey.cancel()select()由于各种神秘的原因,直到下一个才完全生效。您可以尝试selectNow()在取消后拨打电话,或者在重新注册之前拨打电话更好。

于 2013-03-07T01:09:53.663 回答