|
| 1 | +### Java Nio |
| 2 | + |
| 3 | +[参考资料](http://ifeve.com/java-nio-channel-to-channel/) |
| 4 | +[参考资料](http://blog.csdn.net/u013256816/article/details/51457215) |
| 5 | +[参考资料](http://tutorials.jenkov.com/java-nio/selectors.html) |
| 6 | + |
| 7 | +nio是非阻塞性的,面向缓冲区的。 |
| 8 | +nio的目的是为了提高速度,尤其是在文件IO与网络IO中。 |
| 9 | + |
| 10 | +### nio中的几个核心概念 |
| 11 | +通道和缓存器(相当于煤层和运煤车) |
| 12 | + |
| 13 | +* Channels |
| 14 | +* Buffers |
| 15 | +* Selectors |
| 16 | + |
| 17 | +channel,既可以将Buffer中的数据度渠道channel中,也可以将数据输出到buffer中。 |
| 18 | + |
| 19 | +Channel有下面几种类型。 |
| 20 | + |
| 21 | +* FileChannel 文件 |
| 22 | +* DatagramChannel udp |
| 23 | +* SocketChannel 通过tcp读取网络中的数据 |
| 24 | +* ServerSocketChannel 监听新进来的tcp链接,像web服务器那样 |
| 25 | + |
| 26 | +Buffer的类型 |
| 27 | + |
| 28 | +* ByteBuffer |
| 29 | +* CharBuffer |
| 30 | +* DoubleBuffer |
| 31 | +* FloatBuffer |
| 32 | +* IntBuffer |
| 33 | +* LongBuffer |
| 34 | +* ShortBuffer |
| 35 | + |
| 36 | +Selector |
| 37 | + |
| 38 | +Selector允许单线程处理多个Channel。得向Selector注册Channel,然后调用它的select方法。 |
| 39 | + |
| 40 | +_ _ _ |
| 41 | + |
| 42 | +### Channel |
| 43 | + |
| 44 | +* 双向的,既可以写入数据,也可以读取数据 |
| 45 | +* 可以进行异步读写 |
| 46 | +* 总要先读到一个Buffer,或者总要从一个Buffer中写入 |
| 47 | + |
| 48 | +例子 |
| 49 | + |
| 50 | +``` |
| 51 | + try { |
| 52 | + FileChannel fc = new RandomAccessFile("./1.txt","rw").getChannel(); |
| 53 | + ByteBuffer bf = ByteBuffer.allocate(1024); |
| 54 | + //将输入读入buffer |
| 55 | + fc.read(bf); |
| 56 | + bf.flip(); |
| 57 | + while (bf.hasRemaining()){ |
| 58 | + System.err.println((char) bf.get()); |
| 59 | + } |
| 60 | + } catch (FileNotFoundException e) { |
| 61 | + e.printStackTrace(); |
| 62 | + } catch (IOException e) { |
| 63 | + e.printStackTrace(); |
| 64 | + } |
| 65 | +``` |
| 66 | + |
| 67 | +* flip的作用是翻转,意思就是,如果当前为写入状态,如果我们要读取数据,就需要调用他来翻转一下。 |
| 68 | +* hasRemaining是判断是否有下一个byte |
| 69 | + |
| 70 | +如果我们当前为read,我们还想进行以下read操作,那么我们需要调用下clear或者compact清除已经读过的数据,没读过的数据将会 |
| 71 | +被放置在头部方法为每个read做好准备。 |
| 72 | + |
| 73 | +我们可以通过transferTo 和 transferFrom方法来链接两个通道 |
| 74 | + |
| 75 | +_ _ _ |
| 76 | + |
| 77 | +Buffer |
| 78 | + |
| 79 | +Buffer四个索引如下 |
| 80 | + |
| 81 | +* mark 标记 |
| 82 | +* position 位置 |
| 83 | +* limit 界限 |
| 84 | +* capacity 容量 |
| 85 | + |
| 86 | +* limit和capacity位于末尾,position位于首位 |
| 87 | +* 调用mark()方法将mark标记设置为position |
| 88 | +* 调用buffer的get方法将,mark标记往后移 |
| 89 | +* put或者reset方法,将position设置为mark的值 |
| 90 | + |
| 91 | +写入数据 |
| 92 | + |
| 93 | +* read 或 put方法 |
| 94 | + |
| 95 | +从buffer中读数据到channel |
| 96 | + |
| 97 | +* channel的write方法,buf的get方法。 |
| 98 | + |
| 99 | +rewind方法,将position设置为0 |
| 100 | + |
| 101 | +enquals |
| 102 | + |
| 103 | +equals() |
| 104 | + |
| 105 | +当满足下列条件时,表示两个Buffer相等: |
| 106 | + |
| 107 | + 有相同的类型(byte、char、int等)。 |
| 108 | + Buffer中剩余的byte、char等的个数相等。 |
| 109 | + Buffer中所有剩余的byte、char等都相同。 |
| 110 | + |
| 111 | + |
| 112 | +compareTo()方法 |
| 113 | + |
| 114 | +compareTo()方法比较两个Buffer的剩余元素(byte、char等), 如果满足下列条件,则认为一个Buffer“小于”另一个Buffer: |
| 115 | + |
| 116 | + 第一个不相等的元素小于另一个Buffer中对应的元素 。 |
| 117 | + 所有元素都相等,但第一个Buffer比另一个先耗尽(第一个Buffer的元素个数比另一个少)。 |
| 118 | + |
| 119 | +* capacoty() 返回缓冲区容量 |
| 120 | +* clear() 清空缓冲区,position设置0,limit设为容量 |
| 121 | +* flip() limit设为position,position设置为0, |
| 122 | +* remaining() 返回limit-position |
| 123 | +* hasRemaining() 若有介于position和limit之间的 |
| 124 | + |
| 125 | +_ _ _ |
| 126 | + |
| 127 | +### Scatter/Gather |
| 128 | + |
| 129 | +Scatter,从一个Channel中读取的数据分散到n个缓冲区 |
| 130 | +Gather,将N个Buffer里的内容按照顺序发送到一个Channel里。 |
| 131 | + |
| 132 | +read(ByteBuffer[] dsts) |
| 133 | +write(ByteBuffer[] srcs) |
| 134 | + |
| 135 | +### 通道之间的数据传输 |
| 136 | + |
| 137 | +transforFrom可以将数据从源通道传输到目标通道 |
| 138 | +tramstiForm 一样,只不过就是调用顺序不一样。 |
| 139 | + |
| 140 | +### Selector |
| 141 | + |
| 142 | +Selector(选择器)是Java NIO中能够检测一到多个NIO通道,并能够知晓通道是否为诸如读写事件做好准备的组件。 |
| 143 | +这样,一个单独的线程可以管理多个channel,从而管理多个网络连接。 |
| 144 | + |
| 145 | +单个线程管理多个通道 |
| 146 | + |
| 147 | +Selector的创建。 open方法。 |
| 148 | +向Selector注册通道 |
| 149 | + |
| 150 | +channel.configureBlocking(false); |
| 151 | +SelectionKey key = channel.register(selector, |
| 152 | +Selectionkey.OP_READ); |
| 153 | + |
| 154 | +注意register()方法的第二个参数。这是一个“interest集合”,意思是在通过Selector监听Channel时对什么事件感兴趣。可以用|,多个 |
| 155 | +可以监听四种不同类型的事件: |
| 156 | + |
| 157 | +* Connect |
| 158 | +* Accept |
| 159 | +* Read |
| 160 | +* Write |
| 161 | + |
| 162 | +Selector注册Channel时,register()方法会返回一个SelectionKey对象。这个对象包含了一些你感兴趣的属性: |
| 163 | + |
| 164 | + interest集合 |
| 165 | + ready集合 |
| 166 | + Channel |
| 167 | + Selector |
| 168 | + 附加的对象(可选) |
| 169 | + |
| 170 | +interest集合是你所选择的感兴趣的事件集合. |
| 171 | +interest集合,像这样: |
| 172 | +nt interestSet = selectionKey.interestOps(); |
| 173 | +boolean isInterestedInAccept = (interestSet & SelectionKey.OP_ACCEPT) == SelectionKey.OP_ACCEPT; |
| 174 | +boolean isInterestedInConnect = interestSet & SelectionKey.OP_CONNECT; |
| 175 | +boolean isInterestedInRead = interestSet & SelectionKey.OP_READ; |
| 176 | +boolean isInterestedInWrite = interestSet & SelectionKey.OP_WRITE; |
| 177 | + |
| 178 | +可以看到,用“位与”操作interest 集合和给定的SelectionKey常量,可以确定某个确定的事件是否在interest 集合中。 |
| 179 | + |
| 180 | +ready集合 |
| 181 | +ready 集合是通道已经准备就绪的操作的集合。 |
| 182 | +Channel + Selector |
| 183 | + Channel channel = selectionKey.channel(); |
| 184 | + Selector selector = selectionKey.selector(); |
| 185 | + |
| 186 | +附加的对象 |
| 187 | + |
| 188 | +可以将一个对象或者更多信息附着到SelectionKey上,这样就能方便的识别某个给定的通道。例如,可以附加 与通道一起使用的Buffer,或是包含聚集数据的某个对象。使用方法如下: |
| 189 | +查看源代码 |
| 190 | +打印 |
| 191 | +帮助 |
| 192 | +electionKey.attach(theObject); |
| 193 | +Object attachedObj = selectionKey.attachment(); |
| 194 | + |
| 195 | +还可以在用register()方法向Selector注册Channel的时候附加对象。如: |
| 196 | +SelectionKey key = channel.register(selector, SelectionKey.OP_READ, theObject); |
| 197 | + |
| 198 | +通过Selector选择通道 |
| 199 | +select()阻塞到至少有一个通道在你注册的事件上就绪了。 |
| 200 | + |
| 201 | +select(long timeout)和select()一样,除了最长会阻塞timeout毫秒(参数)。 |
| 202 | + |
| 203 | +selectNow()不会阻塞,不管什么通道就绪都立刻返回 |
| 204 | +(译者注:此方法执行非阻塞的选择操作。如果自从前一次选择操作后,没有通道变成可选择的,则此方法直接返回零。)。 |
| 205 | + |
| 206 | +SelectKeys,调用了select方法之后,返回已选择键集中的就绪通道。 |
| 207 | + |
| 208 | +wakeUp() 某个线程调用select()方法后阻塞了,即使没有通道已经就绪,也有办法让其从select()方法返回。 |
| 209 | +只要让其它线程在第一个线程调用select()方法的那个对象上调用Selector.wakeup()方法即可。阻塞在select()方法上的线程会立马返回。 |
| 210 | + |
| 211 | +close 关闭Selector,通道本身不会关闭 |
| 212 | + |
| 213 | +完整的实例。 |
| 214 | + |
| 215 | +_ _ _ |
| 216 | + |
| 217 | +### FileChannel |
| 218 | +file.getChannel() 获取channel |
| 219 | + |
| 220 | +分配一个Buffer,ByteBuffer bb = ByteBuffer.allocate(size). |
| 221 | + |
| 222 | +将数据从channel中读到buffer channel.read(byte) |
| 223 | + |
| 224 | +写入数据 channel.write |
| 225 | + |
| 226 | +### SocketChannel |
| 227 | + |
| 228 | +[参考资料](http://ifeve.com/socket-channel/) |
| 229 | + |
| 230 | +### SocketChannelServer |
| 231 | + |
| 232 | +### DatagramChannel |
| 233 | + |
| 234 | +[实现UDP协议传输](http://blog.csdn.net/foart/article/details/47608475) |
| 235 | + |
| 236 | +* 不需要connet建立链接 |
| 237 | +* 通过send发送数据 |
| 238 | +* 通过receive接受数据 |
| 239 | + |
| 240 | +### Java IO 和 NIO |
| 241 | + |
| 242 | +IO NIO |
| 243 | +面向流 面向缓冲 |
| 244 | +阻塞IO 非阻塞IO |
| 245 | +无 选择器 |
| 246 | + |
| 247 | + |
| 248 | + |
0 commit comments