2、nio的例子实践
下面的例子,说明了,nio中的三大核心类的基本使用。buffer,channel,selector
1 package com.shengsiyuan.nio; 2 3 import org.junit.Test; 4 5 import java.io.*; 6 import java.net.*; 7 import java.nio.ByteBuffer; 8 import java.nio.IntBuffer; 9 import java.nio.MappedByteBuffer; 10 import java.nio.channels.*; 11 import java.nio.channels.spi.SelectorProvider; 12 import java.security.SecureRandom; 13 import java.util.Arrays; 14 import java.util.Iterator; 15 import java.util.Set; 16 17 public class NioTest1 { 18 19 public static void main(String[] args) { 20 IntBuffer intBuffer = IntBuffer.allocate(10); 21 22 for (int i = 0; i < intBuffer.capacity(); i++) { 23 int randomNumber = new SecureRandom().nextInt(20); 24 intBuffer.put(randomNumber); 25 } 26 27 intBuffer.flip();//翻转,从写转到读状态 28 29 while (intBuffer.hasRemaining()) { 30 System.out.println(intBuffer.get()); 31 } 32 33 } 34 35 public void testBuffer() { 36 IntBuffer intBuffer = IntBuffer.allocate(10); 37 38 for (int i = 0; i < intBuffer.capacity(); i++) { 39 int randomNumber = new SecureRandom().nextInt(20); 40 intBuffer.put(randomNumber); 41 } 42 43 intBuffer.flip();//翻转,从写转到读状态 44 45 while (intBuffer.hasRemaining()) { 46 System.out.println(intBuffer.get()); 47 } 48 } 49 50 /** 51 * @ClassName: NioTest1 52 * @Description: 描述 读文件 53 * @Author: 54 * @CreateDate: 2019/8/27 21:26 55 * @Version: 1.0 56 */ 57 @Test 58 public void testChannelRead() { 59 try { 60 FileInputStream fileInputStream = new FileInputStream("NioTest1.txt"); 61 62 FileChannel fileChannel = fileInputStream.getChannel(); 63 64 ByteBuffer byteBuffer = ByteBuffer.allocate(512); 65 66 fileChannel.read(byteBuffer); 67 68 byteBuffer.flip(); 69 70 while(byteBuffer.remaining() > 0) { 71 72 byte b = byteBuffer.get(); 73 System.out.println("char is : " + (char) b); 74 75 if((char)b == 'e') { 76 byteBuffer.mark(); 77 } 78 } 79 80 System.out.println(byteBuffer.position()); 81 System.out.println(byteBuffer.limit()); 82 System.out.println(byteBuffer.capacity()); 83 84 byteBuffer.reset(); 85 86 // System.out.println(byteBuffer.mark()); 87 System.out.println(byteBuffer.position()); 88 System.out.println(byteBuffer.limit()); 89 System.out.println(byteBuffer.capacity()); 90 91 92 fileChannel.close(); 93 fileInputStream.close(); 94 95 } catch (Exception e) { 96 e.printStackTrace(); 97 } 98 } 99 100 /** 101 * @ClassName: NioTest1 102 * @Description: 描述 写文件 103 * @Author: 104 * @CreateDate: 2019/8/27 21:25 105 * @Version: 1.0 106 */ 107 @Test 108 public void testChannelWrite() { 109 try{ 110 FileInputStream fileInputStream = new FileInputStream("NioTest1.txt"); 111 FileChannel fileChannel = fileInputStream.getChannel(); 112 113 FileChannel randowFileChannel = new RandomAccessFile(new File("NioTest1.txt"),"rw").getChannel(); 114 115 ByteBuffer byteBuffer = ByteBuffer.allocate(512); 116 117 byte[] byteArr = "hello nio nihao!".getBytes(); 118 119 byteBuffer.put(byteArr); 120 121 122 byteBuffer.flip(); 123 124 // fileChannel.write(byteBuffer); 125 126 randowFileChannel.write(byteBuffer); 127 }catch (Exception e) { 128 e.printStackTrace(); 129 } 130 } 131 132 /** 133 * @ClassName: NioTest1 134 * @Description: 描述 读写文件 135 * @Author: 136 * @CreateDate: 2019/8/27 21:25 137 * @Version: 1.0 138 */ 139 @Test 140 public void testChannelReadAndWrite() { 141 try { 142 FileInputStream fileInputStream = new FileInputStream("input.txt"); 143 FileOutputStream fileOutputStream = new FileOutputStream("out.txt"); 144 145 FileChannel inputFileChannel = fileInputStream.getChannel(); 146 FileChannel outputFileChannel = fileOutputStream.getChannel(); 147 148 ByteBuffer byteBuffer = ByteBuffer.allocate(512); 149 150 while(inputFileChannel.read(byteBuffer) != -1) { 151 152 byteBuffer.flip(); 153 154 outputFileChannel.write(byteBuffer); 155 156 // byteBuffer.clear(); 157 } 158 159 }catch (Exception e) { 160 e.printStackTrace(); 161 } 162 163 } 164 165 /** 166 * @ClassName: NioTest1 167 * @Description: 描述 切下部分的byteBuffer 作为一个快照,可以实现同步 168 * @Author: 169 * @CreateDate: 2019/8/27 21:24 170 * @Version: 1.0 171 */ 172 @Test 173 public void testSlice() { 174 try{ 175 ByteBuffer byteBuffer = ByteBuffer.allocate(512); 176 177 for (int i = 0; i < 20; i++) { 178 byteBuffer.put((byte)i); 179 } 180 // byteBuffer.flip(); 181 182 ByteBuffer newByteBuffer = byteBuffer.slice(); 183 184 byteBuffer.put((byte)'a'); 185 byteBuffer.put((byte)'b'); 186 187 // newByteBuffer.flip(); 188 System.out.println(newByteBuffer.get(0)); 189 190 // byteBuffer.put(0, (byte)9); 191 192 newByteBuffer.put(0, (byte)9); 193 194 System.out.println(byteBuffer.get(20)); 195 196 System.out.println(newByteBuffer.get(0)); 197 198 199 }catch (Exception e) { 200 e.printStackTrace(); 201 } 202 } 203 204 /** 205 * @ClassName: NioTest1 206 * @Description: 描述 只读的byteBuffer 207 * @Author: 208 * @CreateDate: 2019/8/27 21:24 209 * @Version: 1.0 210 */ 211 @Test 212 public void testReadonlyBuffer() { 213 214 ByteBuffer byteBuffer = ByteBuffer.allocate(512); 215 for (int i = 0; i < 10; i++) { 216 byteBuffer.put((byte)i); 217 } 218 219 ByteBuffer readOnlyBuffer = byteBuffer.asReadOnlyBuffer(); 220 221 readOnlyBuffer.position(0); 222 223 readOnlyBuffer.put((byte)1); 224 225 } 226 227 /** 228 * @ClassName: NioTest1 229 * @Description: 描述 通过直接内存,零拷贝来处理文件 230 * @Author: 231 * @CreateDate: 2019/8/27 21:23 232 * @Version: 1.0 233 */ 234 @Test 235 public void testChannelReadAndWriteDirect() { 236 try { 237 FileInputStream fileInputStream = new FileInputStream("input.txt"); 238 FileOutputStream fileOutputStream = new FileOutputStream("out.txt"); 239 240 FileChannel inputFileChannel = fileInputStream.getChannel(); 241 FileChannel outputFileChannel = fileOutputStream.getChannel(); 242 243 ByteBuffer byteBuffer = ByteBuffer.allocateDirect(512); 244 245 while(inputFileChannel.read(byteBuffer) != -1) { 246 247 byteBuffer.flip(); 248 249 outputFileChannel.write(byteBuffer); 250 251 byteBuffer.clear(); 252 } 253 254 }catch (Exception e) { 255 e.printStackTrace(); 256 } 257 258 } 259 260 /** 261 * @ClassName: NioTest1 内存映射,来修改文件 而不操作buffer 262 * @Description: 描述 263 * @Author: 264 * @CreateDate: 2019/8/27 21:23 265 * @Version: 1.0 266 */ 267 @Test 268 public void testMapBuffer() throws Exception { 269 RandomAccessFile randomAccessFile = new RandomAccessFile("NioTest1.txt", "rw"); 270 FileChannel fileChannel = randomAccessFile.getChannel(); 271 272 MappedByteBuffer mappedByteBuffer = fileChannel.map(FileChannel.MapMode.READ_WRITE, 0, 5); 273 274 mappedByteBuffer.put(0, (byte)'a'); 275 mappedByteBuffer.put(3, (byte)'b'); 276 277 fileChannel.close(); 278 randomAccessFile.close(); 279 } 280 281 282 /** 283 * @ClassName: NioTest1 284 * @Description: 描述 测试 filelock 285 * @Author: 286 * @CreateDate: 2019/8/27 21:30 287 * @Version: 1.0 288 */ 289 @Test 290 public void testFilelock() throws Exception { 291 FileChannel fileChannel = new RandomAccessFile("NioTest1.txt", "rw").getChannel(); 292 293 FileLock fileLock = fileChannel.lock(3, 6, false); 294 295 System.out.println(fileLock.isValid()); 296 System.out.println(fileLock.isShared()); 297 } 298 299 300 /** 301 * @ClassName: NioTest1 302 * @Description: 描述 303 * @Author: 304 * @CreateDate: 2019/8/27 22:36 305 * @Version: 1.0 306 */ 307 @Test 308 public void testScattering() throws Exception { 309 ServerSocketChannel serverSocketChannel = ServerSocketChannel.open(); 310 SocketAddress address = new InetSocketAddress(8899); 311 serverSocketChannel.bind(address); 312 313 SocketChannel socketChannel = serverSocketChannel.accept(); 314 315 int messageLength = 2 + 3 +4; 316 ByteBuffer[] byteBuffers = new ByteBuffer[3]; 317 318 byteBuffers[0] = ByteBuffer.allocate(2); 319 byteBuffers[1] = ByteBuffer.allocate(3); 320 byteBuffers[2] = ByteBuffer.allocate(4); 321 322 while(true) { 323 long readLength = 0; 324 325 //最大读取 messageLength 长度的字符 326 while(readLength < messageLength ) { 327 long r = socketChannel.read(byteBuffers); 328 readLength += r; 329 330 System.out.println("byteBuffer length r is " + r); 331 System.out.println("readLength length r is " + readLength); 332 333 Arrays.asList(byteBuffers).forEach(byteBuffer -> { 334 System.out.println("p:" + byteBuffer.position() + ", l: " +byteBuffer.limit()); 335 }); 336 } 337 338 Arrays.asList(byteBuffers).forEach(byteBuffer -> { 339 byteBuffer.flip(); 340 }); 341 342 long writeLength = 0; 343 //写会去 344 while(writeLength < messageLength) { 345 long w = socketChannel.write(byteBuffers); 346 writeLength += w; 347 System.out.println("byteBuffer length w is " + w); 348 System.out.println("writeLength length w is " + writeLength); 349 350 Arrays.asList(byteBuffers).forEach(byteBuffer -> { 351 System.out.println("p:" + byteBuffer.position() + ", l: " +byteBuffer.limit()); 352 }); 353 } 354 355 Arrays.asList(byteBuffers).forEach(byteBuffer -> byteBuffer.clear()); 356 357 } 358 } 359 360 @Test 361 public void testSelector() throws Exception{ 362 Selector selector = Selector.open(); 363 364 int[] ports = {5000, 5001, 5002, 5003, 5004}; 365 366 for (int i = 0; i < ports.length; i++) { 367 ServerSocketChannel serverSocketChannel = ServerSocketChannel.open(); 368 serverSocketChannel.configureBlocking(false); //变成非阻塞的模式 很重要 369 370 // serverSocketChannel.bind(new InetSocketAddress(ports[i])); 371 372 ServerSocket serverSocket = serverSocketChannel.socket(); 373 //这个bind 直接绑在 serverSocketChannel 可以不 尝试了下,好像区别不大,都可以走通 但是不能重复绑 374 serverSocket.bind(new InetSocketAddress(ports[i])); 375 376 serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT); 377 378 System.out.println("监听:" + ports[i]); 379 } 380 381 while(true) { 382 383 int number = selector.select(); 384 System.out.println("number:" + number); 385 386 Set<SelectionKey> selectionKeys = selector.selectedKeys(); 387 388 Iterator<SelectionKey> keyIterable = selectionKeys.iterator(); 389 390 System.out.println("selectionKeys : " + selectionKeys); 391 392 while(keyIterable.hasNext()) { 393 SelectionKey selectionKey = keyIterable.next(); 394 if(selectionKey.isAcceptable()) {//可接受的 395 ServerSocketChannel serverSocketChannel = (ServerSocketChannel) selectionKey.channel(); 396 //这里为什么还要调accept 因为上面放进去的就是 ServerSocketChannel ,而且没有调accept 接收请求 397 SocketChannel socketChannel = serverSocketChannel.accept(); 398 socketChannel.configureBlocking(false); 399 400 System.out.println("获得链接:" + socketChannel); 401 402 socketChannel.register(selector, SelectionKey.OP_READ); 403 // socketChannel.register(selector, SelectionKey.OP_READ); 重复注册好像不影响 404 405 keyIterable.remove();//如果不remove selectionKeys中会一直存在事件对象 406 } else if(selectionKey.isReadable()) {//可读取的 407 //这里就可以直接用SocketChannel来接收,因为在accept中,是用socketChannel来注册的 408 SocketChannel socketChannel = (SocketChannel) selectionKey.channel(); 409 410 ByteBuffer byteBuffer = ByteBuffer.allocate(512); 411 while(socketChannel.read(byteBuffer) > 0) { 412 byteBuffer.flip(); 413 414 System.out.println("读取到客户端的消息:" + byteBuffer); 415 System.out.println("读取到客户端:" + socketChannel); 416 417 socketChannel.write(byteBuffer); 418 419 byteBuffer.clear(); 420 } 421 422 keyIterable.remove(); 423 424 } 425 426 } 427 428 } 429 430 431 } 432 }