NIO基本编写
一、编写server端
1 public class Server implements Runnable{ 2 //1 多路复用器(管理所有的通道) 3 private Selector seletor; 4 //2 建立缓冲区 5 private ByteBuffer readBuf = ByteBuffer.allocate(1024); 6 //3 7 private ByteBuffer writeBuf = ByteBuffer.allocate(1024); 8 public Server(int port){ 9 try { 10 //1 打开路复用器 11 this.seletor = Selector.open(); 12 //2 打开服务器通道 13 ServerSocketChannel ssc = ServerSocketChannel.open(); 14 //3 设置服务器通道为非阻塞模式 15 ssc.configureBlocking(false); 16 //4 绑定地址 17 ssc.bind(new InetSocketAddress(port)); 18 //5 把服务器通道注册到多路复用器上,并且监听阻塞事件 19 ssc.register(this.seletor, SelectionKey.OP_ACCEPT); 20 21 System.out.println("Server start, port :" + port); 22 23 } catch (IOException e) { 24 e.printStackTrace(); 25 } 26 } 27 28 @Override 29 public void run() { 30 while(true){ 31 try { 32 //1 必须要让多路复用器开始监听 33 System.out.println("1"); 34 this.seletor.select(); 35 System.out.println("2"); 36 //2 返回多路复用器已经选择的结果集 37 Iterator<SelectionKey> keys = this.seletor.selectedKeys().iterator(); 38 //3 进行遍历 39 System.out.println("keys" + keys); 40 while(keys.hasNext()){ 41 //4 获取一个选择的元素 42 SelectionKey key = keys.next(); 43 //5 直接从容器中移除就可以了 44 keys.remove(); 45 //6 如果是有效的 46 if(key.isValid()){ 47 //7 如果为阻塞状态 48 if(key.isAcceptable()){ 49 this.accept(key); 50 } 51 //8 如果为可读状态 52 if(key.isReadable()){ 53 this.read(key); 54 } 55 //9 写数据 56 if(key.isWritable()){ 57 //this.write(key); //ssc 58 } 59 // key.isConnectable() 60 } 61 62 } 63 } catch (IOException e) { 64 e.printStackTrace(); 65 } 66 } 67 } 68 69 private void write(SelectionKey key){ 70 //ServerSocketChannel ssc = (ServerSocketChannel) key.channel(); 71 //ssc.register(this.seletor, SelectionKey.OP_WRITE); 72 } 73 74 private void read(SelectionKey key) { 75 try { 76 //1 清空缓冲区旧的数据 77 this.readBuf.clear(); 78 //2 获取之前注册的socket通道对象 79 SocketChannel sc = (SocketChannel) key.channel(); 80 //3 读取数据 81 int count = sc.read(this.readBuf); 82 //4 如果没有数据 83 if(count == -1){ 84 key.channel().close(); 85 key.cancel(); 86 return; 87 } 88 //5 有数据则进行读取 读取之前需要进行复位方法(把position 和limit进行复位) 89 this.readBuf.flip(); 90 //6 根据缓冲区的数据长度创建相应大小的byte数组,接收缓冲区的数据 91 byte[] bytes = new byte[this.readBuf.remaining()]; 92 //7 接收缓冲区数据 93 this.readBuf.get(bytes); 94 //8 打印结果 95 String body = new String(bytes).trim(); 96 System.out.println("Server : " + body); 97 98 // 9..可以写回给客户端数据 99 } catch (IOException e) { 100 e.printStackTrace(); 101 } 102 103 } 104 105 private void accept(SelectionKey key) { 106 try { 107 //1 获取服务通道 108 ServerSocketChannel ssc = (ServerSocketChannel) key.channel(); 109 //2 执行阻塞方法 110 SocketChannel sc = ssc.accept(); 111 System.out.println("阻塞"); 112 //3 设置阻塞模式 113 sc.configureBlocking(false); 114 //4 注册到多路复用器上,并设置读取标识 115 sc.register(this.seletor, SelectionKey.OP_READ); 116 } catch (IOException e) { 117 e.printStackTrace(); 118 } 119 } 120 121 public static void main(String[] args) { 122 123 new Thread(new Server(8765)).start();; 124 }
二、编写Client端
1 public static void main(String[] args) { 2 3 //创建连接的地址 4 InetSocketAddress address = new InetSocketAddress("127.0.0.1", 8765); 5 6 //声明连接通道 7 SocketChannel sc = null; 8 9 //建立缓冲区 10 ByteBuffer buf = ByteBuffer.allocate(1024); 11 12 try { 13 //打开通道 14 sc = SocketChannel.open(); 15 //进行连接 16 sc.connect(address); 17 18 while(true){ 19 //定义一个字节数组,然后使用系统录入功能: 20 byte[] bytes = new byte[1024]; 21 System.in.read(bytes); 22 23 //把数据放到缓冲区中 24 buf.put(bytes); 25 //对缓冲区进行复位 26 buf.flip(); 27 //写出数据 28 sc.write(buf); 29 //清空缓冲区数据 30 buf.clear(); 31 } 32 } catch (IOException e) { 33 e.printStackTrace(); 34 } finally { 35 if(sc != null){ 36 try { 37 sc.close(); 38 } catch (IOException e) { 39 e.printStackTrace(); 40 } 41 } 42 } 43 44 }