如果检测到连接断开,那么 select 循环就会不断有 read 过来。但我现在对这种情况,有点疑问。
package NonBlocking;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
public class TestDisconnectClient {
static SocketChannel socketChannel = null;
static Selector selector = null;
public static void main(String[] args) throws IOException {
socketChannel = SocketChannel.open(new InetSocketAddress("127.0.0.1",8888));
socketChannel.configureBlocking(false);
selector = Selector.open();
socketChannel.register(selector, SelectionKey.OP_READ);
int result = 0; int i = 1;
while((result = selector.select()) > 0) {
System.out.println(String.format("selector %dth loop, ready event number is %d", i++, result));
Iterator iterator = selector.selectedKeys().iterator();
while (iterator.hasNext()) {
SelectionKey sk = iterator.next();
if (sk.isReadable()) {
System.out.println("有数据可读");
SocketChannel canReadChannel = (SocketChannel)sk.channel();
ByteBuffer buf = ByteBuffer.allocate(1024);
try {
while (canReadChannel.read(buf) > 0) {
buf.flip();
System.out.println(new String(buf.array()));
buf.clear();
}
} catch (IOException e) {
//canReadChannel.close();
//sk.cancel();
System.out.println("检测到远程连接断开");
e.printStackTrace();
//continue;
}
}
iterator.remove();
}
}
}
}
如上这种,先运行服务端、客户度,再停止服务端。发现服务端一直有 read 事件过来,循环不停执行。
} catch (IOException e) {
//canReadChannel.close();
//sk.cancel();
System.out.println("检测到远程连接断开");
e.printStackTrace();
continue;
}
}
iterator.remove();
但如果改成如上这种,select 循环检测到一次 read 事件并抛出异常后,循环就退出了。然后整个程序都退出了。这是为啥啊
} catch (IOException e) {
canReadChannel.close();
sk.cancel();
System.out.println("检测到远程连接断开");
e.printStackTrace();
continue;
}
}
iterator.remove();
如果改成如上这种,select 循环检测到一次 read 事件并抛出异常后,下一次循环继续,但会阻塞在 select 那里。
主要想请教下上面三种情况的差异的原因。
还有就是,正确处理连接断开的方法就是:canReadChannel.close();sk.cancel(); 吗