zoukankan      html  css  js  c++  java
  • 快学Java NIO 续篇

    可以先看Java NIO的整体介绍,这篇接着说以下内容,《快学Java NIO》续篇

    • FileChannel
    • SocketChannel
    • ServerSocketChannel
    • Java NIO DatagramChannel
    • Pipe

    Java NIO Tutorial 地址:http://tutorials.jenkov.com/java-nio/index.html

    Java NIO系列教程译文地址:http://ifeve.com/java-nio-all/

    以下是我拜读过程中摘抄的部分内容,并且加了一些内容、笔记,方便以后再翻阅学习

    FileChannel

    FileChannel是一个连接到文件的通道,可以完成文件读写,总是运行在阻塞模式下。

    之前有代码展示如何从文件中读取数据,以下代码展示如何通过channel写文件

    RandomAccessFile aFile = new RandomAccessFile("data/nio-data.txt",
                 "rw");
    FileChannel channel = aFile.getChannel();
    
    String newData = "New String to write to file..." + System.currentTimeMillis();
    
    //如果设置的大小不够存放newData,会抛异常java.nio.BufferOverflowException
    ByteBuffer buf = ByteBuffer.allocate(48);
    buf.clear();
    buf.put(newData.getBytes());
    
    buf.flip();//limit设置为当前的position,准备读取这个buffer
    
    //FileChannel.write()是在while循环中调用的。
    //因为无法保证write()方法一次能向FileChannel写入多少字节
    //因此需要重复调用write()方法,直到Buffer中已经没有尚未写入通道的字节
    while(buf.hasRemaining()) {
        channel.write(buf);
    }
    channel.close();
    /**
     * 还有如下方法
     * channel.size()//该实例关联文件的大小
     * channel.truncate() 截取文件,指定长度后的部分将被删除
     * channel.force(true);//强制内存数据flush到硬盘
     */

     SocketChannel

    Java NIO中的SocketChannel是一个连接到TCP网络套接字的通道

    可以通过以下2种方式创建SocketChannel:

    • 打开一个SocketChannel并连接到互联网上的某台服务器。
    • 一个新连接到达ServerSocketChannel时,会创建一个SocketChannel。

    从SocketChannel读取数据,写入数据

    SocketChannel socketChannel = SocketChannel.open();
    
    //如果设置非阻塞模式,就可以在异步模式下调用connect(), read() 和write()了。可以进一步和Selector配合。之后章节会涉及
    //socketChannel.configureBlocking(false);
    
    
    //这个需要127.0.0.1的9999端口有进程在监听了,之后会将用ServerSocketChannel监听端口,做服务端
    socketChannel.connect(new InetSocketAddress("127.0.0.1", 9999));
    ByteBuffer buf
    = ByteBuffer.allocate(48);

    //剩下的读写都可以参考fileChannel

    //非阻塞模式时候可以如下等待
    //while(! socketChannel.finishConnect() ){ //wait, or do something else... //}


    //读取数据 int bytesRead = socketChannel.read(buf); System.out.println(bytesRead);

    //写入数据
    String newData = "New String to write to file..." + System.currentTimeMillis(); buf.clear(); buf.put(newData.getBytes()); buf.flip(); while(buf.hasRemaining()) { channel.write(buf); }

    ServerSocketChannel

     Java NIO中的 ServerSocketChannel 是一个可以监听新进来的TCP连接的通道, 就像标准IO中的ServerSocket一样。

    阻塞监听模式

    ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
    
    serverSocketChannel.socket().bind(new InetSocketAddress(9999));
    
    while(true){
        SocketChannel socketChannel =
                serverSocketChannel.accept(); //会一直阻塞到有新连接到达
        System.out.println("a request receive!");
    
        //do something with socketChannel...
    }

    非阻塞模式

    ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
    
    serverSocketChannel.socket().bind(new InetSocketAddress(9999));
    serverSocketChannel.configureBlocking(false);//设置成非阻塞模式
    
    while(true){
        SocketChannel socketChannel =
                serverSocketChannel.accept(); //没有请求会返回null
        
        if(socketChannel != null){
            System.out.println("a request receive!");
        }
      
    }

    Java NIO DatagramChannel

    Java NIO中的DatagramChannel是一个能收发UDP包的通道。因为UDP是无连接的网络协议,所以不能像其它通道那样读取和写入。它发送和接收的是数据包。

    UDP服务端,监听9999端口

    DatagramChannel channel = DatagramChannel.open();
    
    //DatagramChannel可以在UDP端口9999上接收数据包 channel.socket().bind(
    new InetSocketAddress(9999)); ByteBuffer buf = ByteBuffer.allocate(48); buf.clear();
    //receive()方法会将接收到的数据包内容复制到指定的Buffer. 如果Buffer容不下收到的数据,多出的数据将被丢弃

    while(true) {   channel.receive(buf);   System.out.println(buf);
      buf.clear();
    }

    UDP客户端,发送数据到服务端

    DatagramChannel channel = DatagramChannel.open();
    
    String newData = "New String to write to file..." + System.currentTimeMillis();
    
    ByteBuffer buf = ByteBuffer.allocate(48);
    buf.clear();
    buf.put(newData.getBytes());
    buf.flip();
    
    int bytesSent = channel.send(buf, new InetSocketAddress("127.0.0.1", 9999));

    运行服务端后,运行2次客户端,服务端输出

    java.nio.HeapByteBuffer[pos=43 lim=48 cap=48]
    java.nio.HeapByteBuffer[pos=43 lim=48 cap=48]

    Pipe

    Java NIO 管道是2个线程之间的单向数据连接。Pipe有一个source通道和一个sink通道。数据会被写到sink通道,从source通道读取。

    Pipe原理图:

    向管道写数据,从管道读数据,这边方便起见就用一个线程读写管道。其实可以用一个线程写管道,另外一个线程读管道,只要他们共享这个pipe对象就行

    /*
     * 管道是2个线程之间的单向数据连接
     */
    public static void main(String[] args) throws IOException {
        //创建管道
        Pipe pipe = Pipe.open();
        Pipe.SinkChannel sinkChannel = pipe.sink();
        String newData = "New String to write to file..." + System.currentTimeMillis();
        ByteBuffer buf = ByteBuffer.allocate(48);
        buf.clear();
        buf.put(newData.getBytes());
    
        buf.flip();
    
        //往sink Channel里写数据
        while(buf.hasRemaining()) {
            sinkChannel.write(buf);
        }
        
        //可以往source Channel读数据
        Pipe.SourceChannel sourceChannel = pipe.source();
    
        buf.clear();
        int bytesRead = sourceChannel.read(buf);
        //read()方法返回的int值会告诉我们多少字节被读进了缓冲区
        System.out.println("bytesRead:"+bytesRead);
    }
  • 相关阅读:
    2016个人测试1(待续。。。)
    bzoj2548[Cstc2002]灭鼠行动
    noip2013 积木大赛
    noip2013 火柴排队
    Noip2000 T3 单词接龙
    noip2017爆炸记——题解&总结&反省(普及组+提高组)
    【2017.10.26-】后缀数组学习笔记
    20171002清北
    【搜索党】卡时技巧
    【noip】noip201503求和(题解可能不完美,但绝对详细)
  • 原文地址:https://www.cnblogs.com/yanghuahui/p/3683868.html
Copyright © 2011-2022 走看看