Netty学习第六节实例一步学习

NIO与传统IO对应使用的类:
ServerSocketChannel相当于ServerSocket
SocketChannel 相当于Socket
Selector是NIO的核心类,是负责监听ServerSocketChannel和SocketChannel 
(所以NIO是可以实现单线程为多个客户端服务的,而传统IO是不可以的)
SelectionKey 返回的监听结果
 
原理实例解析:
比如如果餐厅是一个系统的话,serverSocket相当于一个餐厅的大门,只负责大门的看护(监视),也就是监听端口,客人就是socket,所有客人都需要通过大门进入餐厅,餐厅的服务员就相当于一个线程,传统socket是一个如图的模型(一个服务员服务一个客人):
 
 
如果NIO也是以一个餐厅系统,它的大门就是ServerSocketChannel ,客户端就是SocketChannel,服务员就是(线程+Selector),其服务员增加了selector能力,即为多个客户服务的能力,同时可以监听大门(欢迎新的客人),如图所示:
 
Selector.select()============无法看到源码,底层是基于C实现的.
实例代码:
  1 package com.NIO;
  2 
  3 import java.io.IOException;
  4 import java.net.InetSocketAddress;
  5 import java.nio.ByteBuffer;
  6 import java.nio.channels.SelectionKey;
  7 import java.nio.channels.Selector;
  8 import java.nio.channels.ServerSocketChannel;
  9 import java.nio.channels.SocketChannel;
 10 import java.util.Iterator;
 11 
 12 /**
 13  * NIO服务端
 14  * 
 15  * @author -琴兽-
 16  */
 17 public class NIOServer {
 18     // 通道管理器
 19     private Selector selector;
 20 
 21     /**
 22      * 获得一个ServerSocket通道,并对该通道做一些初始化的工作
 23      * 
 24      * @param port
 25      *            绑定的端口号
 26      * @throws IOException
 27      */
 28     public void initServer(int port) throws IOException {
 29         // 获得一个ServerSocket通道
 30         ServerSocketChannel serverChannel = ServerSocketChannel.open();
 31         // 设置通道为非阻塞
 32         serverChannel.configureBlocking(false);
 33         // 将该通道对应的ServerSocket绑定到port端口
 34         serverChannel.socket().bind(new InetSocketAddress(port));
 35         // 获得一个通道管理器
 36         this.selector = Selector.open();
 37         // 将通道管理器和该通道绑定,并为该通道注册SelectionKey.OP_ACCEPT事件,注册该事件后,
 38         // 当该事件到达时,selector.select()会返回,如果该事件没到达selector.select()会一直阻塞。
 39         serverChannel.register(selector, SelectionKey.OP_ACCEPT);
 40     }
 41 
 42     /**
 43      * 采用轮询的方式监听selector上是否有需要处理的事件,如果有,则进行处理
 44      * 
 45      * @throws IOException
 46      */
 47     public void listen() throws IOException {
 48         System.out.println("服务端启动成功!");
 49         // 轮询访问selector
 50         while (true) {
 51             // 当注册的事件到达时,方法返回;否则,该方法会一直阻塞
 52             selector.select();
 53             // 获得selector中选中的项的迭代器,选中的项为注册的事件
 54             Iterator<?> ite = this.selector.selectedKeys().iterator();
 55             while (ite.hasNext()) {
 56                 SelectionKey key = (SelectionKey) ite.next();
 57                 // 删除已选的key,以防重复处理
 58                 ite.remove();
 59 
 60                 handler(key);
 61             }
 62         }
 63     }
 64 
 65     /**
 66      * 处理请求
 67      * 
 68      * @param key
 69      * @throws IOException
 70      */
 71     public void handler(SelectionKey key) throws IOException {
 72         
 73         // 客户端请求连接事件
 74         if (key.isAcceptable()) {
 75             handlerAccept(key);
 76             // 获得了可读的事件
 77         } else if (key.isReadable()) {
 78             handelerRead(key);
 79         }
 80     }
 81 
 82     /**
 83      * 处理连接请求
 84      * 
 85      * @param key
 86      * @throws IOException
 87      */
 88     public void handlerAccept(SelectionKey key) throws IOException {
 89         ServerSocketChannel server = (ServerSocketChannel) key.channel();
 90         // 获得和客户端连接的通道
 91         SocketChannel channel = server.accept();
 92         // 设置成非阻塞
 93         channel.configureBlocking(false);
 94 
 95         // 在这里可以给客户端发送信息哦
 96         System.out.println("新的客户端连接");
 97         // 在和客户端连接成功之后,为了可以接收到客户端的信息,需要给通道设置读的权限。
 98         channel.register(this.selector, SelectionKey.OP_READ);
 99     }
100 
101     /**
102      * 处理读的事件
103      * 
104      * @param key
105      * @throws IOException
106      */
107     public void handelerRead(SelectionKey key) throws IOException {
108         // 服务器可读取消息:得到事件发生的Socket通道
109         SocketChannel channel = (SocketChannel) key.channel();
110         // 创建读取的缓冲区
111         ByteBuffer buffer = ByteBuffer.allocate(1024);
112         int read = channel.read(buffer);
113         if(read > 0){
114             byte[] data = buffer.array();
115             String msg = new String(data).trim();
116             System.out.println("服务端收到信息:" + msg);
117             
118             //回写数据
119             ByteBuffer outBuffer = ByteBuffer.wrap("好的".getBytes());
120             channel.write(outBuffer);// 将消息回送给客户端
121         }else{
122             System.out.println("客户端关闭");
123             key.cancel();
124         }
125     }
126 
127     /**
128      * 启动服务端测试
129      * 
130      * @throws IOException
131      */
132     public static void main(String[] args) throws IOException {
133         NIOServer server = new NIOServer();
134         server.initServer(8000);
135         server.listen();
136     }
137 
138 }
View Code
原文地址:https://www.cnblogs.com/liuyangfirst/p/8763591.html