Netty学习-02

来源:互联网 发布:网络融资平台靠谱吗 编辑:程序博客网 时间:2024/05/17 21:02

Demon3:

package com.study.netty.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;public class NIOServerTest {// 通道管理器private Selector selector;/** * 获得一个ServerSocket通道,并对该通道做一些初始化的工作 *  * @param port *            绑定的端口号 * @throws IOException */public void initServer(int port) throws IOException {// 获得一个ServerSocket通道ServerSocketChannel serverChannel = ServerSocketChannel.open();// 设置通道为非阻塞serverChannel.configureBlocking(false);// 将该通道对应的ServerSocket绑定到port端口serverChannel.socket().bind(new InetSocketAddress(port));// 获得一个通道管理器this.selector = Selector.open();// 将通道管理器和该通道绑定,并为该通道注册SelectionKey.OP_ACCEPT事件,注册该事件后,// 当该事件到达时,selector.select()会返回,如果该事件没到达selector.select()会一直阻塞。serverChannel.register(selector, SelectionKey.OP_ACCEPT);}/** * 采用轮询的方式监听selector上是否有需要处理的事件,如果有,则进行处理 *  * @throws IOException */public void listen() throws IOException {System.out.println("服务端启动成功!");// 轮询访问selectorwhile (true) {// 当注册的事件到达时,方法返回;否则,该方法会一直阻塞selector.select();// 获得selector中选中的项的迭代器,选中的项为注册的事件Iterator<?> ite = this.selector.selectedKeys().iterator();while (ite.hasNext()) {SelectionKey key = (SelectionKey) ite.next();// 删除已选的key,以防重复处理ite.remove();handler(key);}}}/** * 处理请求 *  * @param key * @throws IOException */public void handler(SelectionKey key) throws IOException {// 客户端请求连接事件if (key.isAcceptable()) {handlerAccept(key);// 获得了可读的事件} else if (key.isReadable()) {handelerRead(key);}}/** * 处理连接请求 *  * @param key * @throws IOException */public void handlerAccept(SelectionKey key) throws IOException {ServerSocketChannel server = (ServerSocketChannel) key.channel();// 获得和客户端连接的通道SocketChannel channel = server.accept();// 设置成非阻塞channel.configureBlocking(false);// 在这里可以给客户端发送信息哦System.out.println("新的客户端连接");// 在和客户端连接成功之后,为了可以接收到客户端的信息,需要给通道设置读的权限。channel.register(this.selector, SelectionKey.OP_READ);}/** * 处理读的事件 *  * @param key * @throws IOException */public void handelerRead(SelectionKey key) throws IOException {// 服务器可读取消息:得到事件发生的Socket通道SocketChannel channel = (SocketChannel) key.channel();// 创建读取的缓冲区ByteBuffer buffer = ByteBuffer.allocate(1024);int read = channel.read(buffer);if(read > 0){byte[] data = buffer.array();String msg = new String(data).trim();System.out.println("服务端收到信息:" + msg);//回写数据ByteBuffer outBuffer = ByteBuffer.wrap("OK".getBytes());channel.write(outBuffer);// 将消息回送给客户端}else{System.out.println("客户端关闭");key.cancel();}}/** * 启动服务端测试 *  * @throws IOException */public static void main(String[] args) throws IOException {NIOServerTest server = new NIOServerTest();server.initServer(8000);server.listen();}}

以上代码可以在debug下模拟调用过程;

NIO图:

socketIO:



NIO的特点
ServerSocketChannel ServerSocket
SocketChannel Socket
Selector
SelectionKey

NIO的一些疑问
1、客户端关闭的时候会抛出异常,死循环
解决方案
int read = channel.read(buffer);
if(read > 0){
byte[] data = buffer.array();
String msg = new String(data).trim();
System.out.println("服务端收到信息:" + msg);

//回写数据
ByteBuffer outBuffer = ByteBuffer.wrap("好的".getBytes());
channel.write(outBuffer);// 将消息回送给客户端
}else{
System.out.println("客户端关闭");
key.cancel();
}

2、selector.select();阻塞,那为什么说nio是非阻塞的IO?
selector.select()
selector.select(1000);不阻塞
selector.wakeup();也可以唤醒selector
selector.selectNow();也可以立马返还,视频里忘了讲了,哈,这里补上

3、SelectionKey.OP_WRITE是代表什么意思
     OP_WRITE表示底层缓冲区是否有空间,是则响应返还true