一步一步理解Java NIO(下)

来源:互联网 发布:mysql分页limit0,1 编辑:程序博客网 时间:2024/06/05 14:22

阻塞与非阻塞IO

选择器Selector


首先来看阻塞式网络IO通信:

package NIOTest;import org.junit.Test;import java.io.IOException;import java.net.InetSocketAddress;import java.nio.ByteBuffer;import java.nio.channels.FileChannel;import java.nio.channels.ServerSocketChannel;import java.nio.channels.SocketChannel;import java.nio.file.Paths;import java.nio.file.StandardOpenOption;/** * Created by yangl on 2017/7/7. * NIO完成网络通信的三个核心 * 1.通道(Channel):负责连接 *      java.nio.channels.Channel *          |--SelcectableChannel *           |--SocketChannel *           |--ServerSocketChannel *           |--DatagramChannel * *           |--Pipe.SinkChannel *           |--Pipe.SourceChannel * 2.缓冲区(Buffer):负责数据的存取 * * 3.选择器(Selector):是SelectableChannel的多路复用器,用于监控SelectableChannel的IO状况 */public class NIO_Blocking2 {    @Test    public void client() throws IOException    {        //获取通道        SocketChannel socketChannel = SocketChannel.open(new InetSocketAddress("127.0.0.1",9898));        FileChannel inChannel = FileChannel.open(Paths.get("C:\\MyCode\\Java\\JavaTest\\src\\NIOTest\\1.jpg"), StandardOpenOption.READ);        //分配指定大小的额缓冲区        ByteBuffer buf = ByteBuffer.allocate(1024);        //读取本地文件,并发送到服务端        while(inChannel.read(buf) != -1)        {            buf.flip();            socketChannel.write(buf);            buf.clear();        }        socketChannel.shutdownOutput();        //接受服务端的反馈        int len = 0;        while (socketChannel.read(buf) != -1)        {            buf.flip();            System.out.println(new String(buf.array(),0,len));            buf.clear();        }        inChannel.close();        socketChannel.close();    }    @Test    public void server() throws IOException    {        //获取通道        ServerSocketChannel ssChannel = ServerSocketChannel.open();        FileChannel outChannel = FileChannel.open(Paths.get("C:\\MyCode\\Java\\JavaTest\\src\\NIOTest\\2.jpg"),StandardOpenOption.WRITE,StandardOpenOption.CREATE);        //绑定连接        ssChannel.bind(new InetSocketAddress(9898));        //获取客户端连接的通道        SocketChannel sChannel = ssChannel.accept();        //分配指定大小的缓冲区        ByteBuffer buf = ByteBuffer.allocate(1024);        //获取客户端的数据,并保存到本地        while(sChannel.read(buf) != -1) {            buf.flip();            outChannel.write(buf);            buf.clear();        }        //发送反馈给客户端        buf.put("服务端接收数据成功".getBytes());        buf.flip();        sChannel.write(buf);        sChannel.close();        ssChannel.close();        outChannel.close();    }}

Selector的应用

package NIOTest;import org.junit.Test;import sun.nio.ch.SelChImpl;import java.io.IOException;import java.net.InetSocketAddress;import java.nio.ByteBuffer;import java.nio.channels.*;import java.nio.file.Paths;import java.nio.file.StandardOpenOption;import java.util.Date;import java.util.Iterator;import java.util.Scanner;/** * Created by yangl on 2017/7/7. * NIO完成网络通信的三个核心 * 1.通道(Channel):负责连接 *      java.nio.channels.Channel *          |--SelcectableChannel *           |--SocketChannel *           |--ServerSocketChannel *           |--DatagramChannel * *           |--Pipe.SinkChannel *           |--Pipe.SourceChannel * 2.缓冲区(Buffer):负责数据的存取 * * 3.选择器(Selector):是SelectableChannel的多路复用器,用于监控SelectableChannel的IO状况 */public class NIO_NonBlocking {    @Test    public void client() throws IOException    {        //获取通道        SocketChannel socketChannel = SocketChannel.open(new InetSocketAddress("127.0.0.1",9898));        //切换成非阻塞模式        socketChannel.configureBlocking(false);        //分配指定大小的额缓冲区        ByteBuffer buf = ByteBuffer.allocate(1024);        //4. 发送数据给服务端        Scanner scan = new Scanner(System.in);        while(scan.hasNext()){            String str = scan.next();            buf.put((new Date().toString() + "\n" + str).getBytes());            buf.flip();            socketChannel.write(buf);            buf.clear();        }        socketChannel.close();    }    @Test    public void server() throws IOException    {        System.out.println("Server ......");        //获取通道        ServerSocketChannel ssChannel = ServerSocketChannel.open();        //切换成非阻塞模式        ssChannel.configureBlocking(false);        //绑定连接        ssChannel.bind(new InetSocketAddress(9898));        //获取选择器        Selector selector = Selector.open();        //将通道注册到选择器,并且指定监听事件        ssChannel.register(selector,SelectionKey.OP_ACCEPT);        //轮训地获取选择器上准备就绪的事件        while (selector.select() > 0)        {            //获取当前选择器中所有注册的“选择键”(已经就绪的监听事件)            Iterator<SelectionKey> it = selector.selectedKeys().iterator();            while (it.hasNext()){                //获取准备就绪的事件                SelectionKey sk = it.next();                //判断就绪事件的类型                if (sk.isAcceptable()){                    SocketChannel socketChannel = ssChannel.accept();                    //切换非阻塞模式                    socketChannel.configureBlocking(false);                    //将通道注册到选择器上                    socketChannel.register(selector,SelectionKey.OP_READ);                }                else if (sk.isReadable()){                    SocketChannel socketChannel2 = (SocketChannel)sk.channel();                    //读取数据                    ByteBuffer buf = ByteBuffer.allocate(1024);                    int len = 0;                    while ((len = socketChannel2.read(buf)) > 0){                        buf.flip();                        System.out.println(new String(buf.array(),0,len));                        buf.clear();                    }                    it.remove();                }            }        }    }}
原创粉丝点击