socketchannel在客户端链接断开时的问题
- public class ReaderLookup
- {
- private static final int PORT = 8888;
- // private Map<Reader,SocketChannel> readerCache = new Hashtable<Reader, SocketChannel>();
- private List<SelectionKey> keyCache = new ArrayList<SelectionKey>();
- public void lookupAllReaders(){
- try
- {
- // Create a new server socket channel and set to non blocking mode
- ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
- serverSocketChannel.configureBlocking(false);
- // Bind the server socket to local host
- ServerSocket serverSocket = serverSocketChannel.socket();
- serverSocket.bind(new InetSocketAddress(InetAddress.getLocalHost(),PORT));
- // Get a selector
- Selector selector = Selector.open();
- // Register accepts on the server socket with the selector. This
- // step tells the selector that the socket wants to be put on the
- // ready list when accept operations occur, so allowing multiplexed
- // non-blocking I/O to take place.
- SelectionKey key_ServerSocketChannel = serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
- int keys = 0 ;
- while( (keys = selector.select()) > 0 ){
- // Get selected keys
- Set selectedKeys = selector.selectedKeys();
- Iterator iterator = selectedKeys.iterator();
- while (iterator.hasNext())
- {
- SelectionKey key = (SelectionKey) iterator.next();
- iterator.remove();
- if(key.isAcceptable()){
- ServerSocketChannel tmpServerSocketChannel = (ServerSocketChannel) key.channel();
- // The accept() returned immediately because the ServerSocketChannel was working on non-blocking mode
- SocketChannel client = tmpServerSocketChannel.accept();
- // 最好不要注册写状态SelectionKey.OP_WRITE,因为写状态在任何时候都是ready的,都会被select(),影响性能
- client.configureBlocking(false);
- SelectionKey clientKey = client.register(selector, SelectionKey.OP_READ);
- // Save the client channel's selectionkey for write databuffer
- keyCache.add(clientKey);
- }else if(key.isReadable()){
- System.out.println(key.readyOps());
- int dataLength = 4;
- ByteBuffer dst = ByteBuffer.allocate(dataLength);
- SocketChannel socketChannel = (SocketChannel) key.channel();
- socketChannel.read(dst);
- // dst.flip();
- // // Do something with the bytebuffer
- dst.flip();
- Charset charset = Charset.forName("us-ascii");
- CharsetDecoder decoder = charset.newDecoder();
- CharBuffer charBuffer = decoder.decode(dst);
- if(charBuffer.toString().equals("w")){
- writeMsg(socketChannel.keyFor(selector));
- }else{
- dst.flip();
- socketChannel.write(dst);
- }
- // System.out.println(charBuffer.toString());
- }
- }
- }
- }
- catch (IOException e)
- {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- }
- private void writeMsg(SelectionKey selectionKey) throws IOException
- {
- // TODO Auto-generated method stub
- ByteBuffer bf = ByteBuffer.wrap("It isn't through selector!".getBytes());
- ((SocketChannel)selectionKey.channel()).write(bf);
- }
- public static void main(String[] args)
- {
- ReaderLookup main = new ReaderLookup();
- main.lookupAllReaders();
- }
- }
当客户端的链接异常断开,此时代表这个链接的channel一直处于readable的状态,如何检查链接已断开呢?
一段时间的试验发现,链接断开后,虽然该channel的ready operation是OP_READ,但是此时channel.read(buffer)返回-1,此时可以增加一个判断
- while( (keys = selector.select()) > 0 ){
- // Get selected keys
- Set selectedKeys = selector.selectedKeys();
- Iterator iterator = selectedKeys.iterator();
- while (iterator.hasNext())
- {
- SelectionKey key = (SelectionKey) iterator.next();
- iterator.remove();
- if(key.isAcceptable()){
- ServerSocketChannel tmpServerSocketChannel = (ServerSocketChannel) key.channel();
- // The accept() returned immediately because the ServerSocketChannel was working on non-blocking mode
- SocketChannel client = tmpServerSocketChannel.accept();
- // 最好不要注册写状态SelectionKey.OP_WRITE,因为写状态在任何时候都是ready的,都会被select(),影响性能
- client.configureBlocking(false);
- SelectionKey clientKey = client.register(selector, SelectionKey.OP_READ );
- // Save the client channel's selectionkey for write databuffer
- keyCache.add(clientKey);
- }else if(key.isReadable()){
- SocketChannel socketChannel = (SocketChannel) key.channel();
- ByteBuffer dstBuffer = ByteBuffer.allocate(BUFFER_SIZE);
- int count ;
- while( (count = socketChannel.read(dstBuffer)) > 0){
- dstBuffer.flip();
- // Do something with the bytebuffer
- Charset charset = Charset.forName("us-ascii");
- CharsetDecoder decoder = charset.newDecoder();
- CharBuffer charBuffer = decoder.decode(dstBuffer);
- if(charBuffer.toString().equals("w")){
- writeMsg(socketChannel.keyFor(selector));
- }else{
- dstBuffer.flip();
- socketChannel.write(dstBuffer);
- }
- dstBuffer.clear();
- }//end while( (count = socketChannel.read(dst)) > 0){
- //链接异常中断,关闭channel
- if(count < 0){
- socketChannel.close();
- }
- }//end else if(key.isReadable()){
- }//end while (iterator.hasNext())
- }//end while( (keys = selector.select()) > 0 ){
- }
//链接异常中断,关闭channel
if(count < 0){
socketChannel.close();
}
梅花香自苦寒来
浙公网安备 33010602011771号