02_NIO简单实例
【一个用NIO实现的客户端向服务端单向通信的例子】
【服务端程序】
package com.nio.test; import java.io.IOException; import java.net.InetSocketAddress; import java.nio.ByteBuffer; import java.nio.channels.SelectionKey; import java.nio.channels.Selector; import java.nio.channels.ServerSocketChannel; import java.nio.channels.SocketChannel; import java.util.Iterator; /** * Created by cuixinjie on 2018/5/30. */ public class Server implements Runnable{ //1.多路复用器(管理所有的Channel) private Selector selector; //2.建立缓冲区 private ByteBuffer readBuffer = ByteBuffer.allocate(1024); public Server(int port){ try { //1.打开多路复用器 this.selector = Selector.open(); //2.打开服务端通道Channel ServerSocketChannel ssc = ServerSocketChannel.open(); //3.设置服务器通道为非阻塞模式 ssc.configureBlocking(false); //4.绑定地址 ssc.bind(new InetSocketAddress(port)); //5.把服务器通道ssc注册到多路复用器selector上,并且监听阻塞事件 ssc.register(this.selector, SelectionKey.OP_ACCEPT); System.out.println("服务端已启动,监听port:"+port); }catch (IOException e){ e.printStackTrace(); } } @Override public void run() { while (true){ try{ //1.让多路复用器开始监听 this.selector.select(); //2.返回多路复用器已经选择的Key结果集 Iterator<SelectionKey> keys = this.selector.selectedKeys().iterator(); //3.进行遍历 while (keys.hasNext()){ //4.获取一个选择的的元素 SelectionKey key = keys.next(); //5.直接从容器中移除 keys.remove(); //6.如果是有效的 if(key.isValid()){ //7.如果是阻塞状态 if(key.isAcceptable()){ this.accept(key); } //8.如果是可读状态 if(key.isReadable()){ this.read(key); } } } }catch (IOException e){ e.printStackTrace(); } } } private void accept(SelectionKey key){ try{ //1.获取服务端通道 ServerSocketChannel ssc = (ServerSocketChannel)key.channel(); //2.执行阻塞方法 SocketChannel sc = ssc.accept(); //注意:这里会一直阻塞到客户端的请求过来! //3.设置阻塞模式 sc.configureBlocking(false); //4.注册到多路复用器上,并设置读取标识 sc.register(this.selector,SelectionKey.OP_READ); }catch (IOException e){ e.printStackTrace(); } } private void read(SelectionKey key ){ try{ //1.清空缓冲区旧的数据 this.readBuffer.clear(); //2.获取之前注册的Socket通道对象 SocketChannel sc = (SocketChannel)key.channel(); //3.读取数据 int count = sc.read(this.readBuffer); //4.如果没有数据 if(count== -1){ key.channel().close(); key.cancel(); return; } //5.有数据则进行数据读取,读取之前需要进行复位方法(把position 和 limit进行复位) this.readBuffer.flip(); //6.根据缓冲区的数据长度创建相应大小的byte数组,接收缓冲区的数据 byte[] bytes = new byte[this.readBuffer.remaining()]; //7.接收缓冲区数据 this.readBuffer.get(bytes); //8.打印结果 String body = new String(bytes).trim(); System.out.println("服务端收到客户端的内容为:"+body); }catch (IOException e){ e.printStackTrace(); } } public static void main(String[] args) { new Thread(new Server(8765)).start(); } }
【客户端程序】
package com.nio.test; import java.io.IOException; import java.net.InetSocketAddress; import java.nio.ByteBuffer; import java.nio.channels.SocketChannel; /** * Created by cuixinjie on 2018/5/30. */ public class Client { public static void main(String[] args) { //创建连接的地址 InetSocketAddress address = new InetSocketAddress("127.0.0.1",8765); //声明连接通道 SocketChannel sc = null; //建立缓冲区 ByteBuffer buf = ByteBuffer.allocate(1024); try{ //打开通道 sc = SocketChannel.open(); //进行连接 sc.connect(address); while(true){ //定义一个字节数组,然后使用系统录入功能 byte[] bytes = new byte[1024]; System.out.print("客户端发送的数据为:"); System.in.read(bytes); //把数据的数据放入缓冲区中 buf.put(bytes); //对缓冲区进行复位 buf.flip(); //写出数据 sc.write(buf); //清空缓冲区数据 buf.clear(); } }catch (IOException e){ e.printStackTrace(); }finally { if(null!=sc){ try{ sc.close(); }catch (IOException e){ e.printStackTrace(); } } } } }
【运行结果】
1.先启动服务端
2.再启动客户端,并输入需要传输的数据
3.再查看服务端接受的数据