且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

NIO的那些事儿

更新时间:2022-09-16 23:24:16

1. 只有非阻塞Channel才能注册,否则会报IllegalBlockingModeException


2. sk.interestOps(sk.interestOps()& ~SelectionKey.OP_READ);

    //处理业务

  sk.interestOps(sk.interestOps()| SelectionKey.OP_READ);

 sk.interestOps()操作必须在与register()操作在同一个线程,否则不起作用。这个观点被证明是错的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
package com.guojje.nio;
 
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.ReadableByteChannel;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.nio.channels.spi.SelectorProvider;
import java.util.Iterator;
import java.util.Set;
 
public class NioServer {
    public static void main(String[] args) throws IOException,
            InterruptedException {
        ServerSocketChannel ssc = ServerSocketChannel.open();
        ssc.bind(new InetSocketAddress("0.0.0.0"8080));
    
        // Thread.currentThread().sleep(100000);
        ssc.configureBlocking(false);
        Selector selector = SelectorProvider.provider().openSelector();
        ssc.register(selector, SelectionKey.OP_ACCEPT);
 
        while (true) {
            int readyChannels = selector.select();
            System.out.println("ready channels count:" + readyChannels);
            if (readyChannels > 0) {
                Set<SelectionKey> selectedKeys = selector.selectedKeys();
                 
                Iterator<SelectionKey> it = selectedKeys.iterator();
                 
                while(it.hasNext()){
                     
                    SelectionKey sk = it.next();
                    it.remove();
                     
                    if((sk.readyOps() & SelectionKey.OP_ACCEPT) != 0){
                        ServerSocketChannel  serverChannel = (ServerSocketChannel)sk.channel();
                        SocketChannel sc = serverChannel.accept();
                        System.out.println(sc);
                        sc.configureBlocking(false);
                        sc.register(selector, SelectionKey.OP_READ);
                    }
                     
                    if((sk.readyOps() & SelectionKey.OP_READ) != 0){
                        ReadableByteChannel rc = (ReadableByteChannel)sk.channel();
                        sk.interestOps(sk.interestOps() & ~SelectionKey.OP_READ);
                        ByteBuffer bb = ByteBuffer.allocate(50);
                        rc.read(bb);
                        System.out.println(new String(bb.array(),0,bb.position()));
                        //sk.interestOps(sk.interestOps() | SelectionKey.OP_READ);
                        Thread anoThread = new Thread(new AnotherThread(sk));
                        anoThread.start();
                        anoThread.join();
                    }
                     
                }
            }
 
        }
 
    }
}
 
package com.guojje.nio;
 
import java.nio.channels.SelectionKey;
 
public class AnotherThread implements Runnable {
     private SelectionKey sk;
      
     public AnotherThread(SelectionKey sk){
          this.sk = sk;
     }
 
    @Override
    public void run() {
        sk.interestOps(sk.interestOps() | SelectionKey.OP_READ);
    }
}

三、 一个数组byte[] bs = new byte[10],bs[0]=10, bs[1]=9, bs[2]=8

如果想把SocketChannel读入剩余7个元素,而不影响其他,可以这样:

ByteBuffer bb = ByteBuffer.wrap(bs,3,7).slice();

如果仅仅用ByteBuffer.wrap(bs,3,7),则bb的capacity仍为bs.length.

而用slice之后,bb的capacity为7,所以你对bb的任务操作都不会影响到前三个元素。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
package com.guojje.nio;
 
import java.nio.ByteBuffer;
 
public class TestSlice {
  public static void main(String[] args) {
      byte[] bs = new byte[10];
      bs[0]=10;
      bs[1]=9
      bs[2]=8;
       
      ByteBuffer bb1 = ByteBuffer.wrap(bs,3,7);
      ByteBuffer bb2 = ByteBuffer.wrap(bs,3,7).slice();
       
      System.out.println(bb1.capacity());
      System.out.println(bb2.capacity());
}
}

四、 ByteBuffer.put ()与 ByteBuffer.get()都会增长position,并且上限都是limit.

因为:

1
2
3
4
5
 final int nextGetIndex() {                          // package-private
        if (position >= limit)
            throw new BufferUnderflowException();
        return position++;
    }
1
2
3
4
5
 final int nextPutIndex() {                          // package-private
        if (position >= limit)
            throw new BufferOverflowException();
        return position++;
    }

position都会增长。


 一个 channal 对应同一个SelectionKey in the same selector

六、channel.register操作may block if invoked concurrently with another registration[another.register(...)] 

   or selection operation[selector.select(...)] involving in the same selector.

   这是因为register操作需要regLock与keyLock锁。


七. selectionKey.cancel():

   The key will be removed from all of the selector's key sets during the next selection operation[select(...)] 

    cancel may block briefly if invoked concurrently with a cancellation[cancel()] or selection operation[select(...)] 

    involving the same selector.

参考:http://www.blogjava.net/adapterofcoms/archive/2010/03/02/314242.html


本文转自 anranran 51CTO博客,原文链接:http://blog.51cto.com/guojuanjun/642680