Java NIO小案例

package com.gsau.NIO;

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;
/**
 * @Description:  创建NIOServer
 * @Date: 2018/9/12 13:16
 * @author: wgq
 * @version: 1.0
 * @param:
 */
public class NIOServer {
    private Selector selector;                                            // 通道管理器
    /**
    * @Description: 获得一个通道并且做一些初始化的工作(为他注册一个Selector)
    * @Date: 2018/9/12 13:17
    * @author: wgq
    * @version: 1.0
    * @param: 
    */
    public void initServer(int port) throws IOException {
        ServerSocketChannel serverChannel = ServerSocketChannel.open();    // 获得一个ServerSocket通道,相当于传统socket中的ServerSocket
        serverChannel.configureBlocking(false);                            // 设置通道为非阻塞
        serverChannel.socket().bind(new InetSocketAddress(port));          // 将该通道对应的ServerSocket绑定到port端口,ip默认就是本机的ip
        this.selector = Selector.open();                                   // 获得一个通道管理器
        serverChannel.register(selector, SelectionKey.OP_ACCEPT);          // 将通道管理器和该通道绑定,并为该通道注册SelectionKey.OP_ACCEPT事件,注册该事件后,当该事件到达时selector.select()会返回,如果该事件没到达selector.select()会一直阻塞
    }
    /**
    * @Description:  采用轮询的方式监听selector上是否有需要处理的事件,如果有,则进行处理
    * @Date: 2018/9/12 13:19
    * @author: wgq
    * @version: 1.0
    * @param: 
    */
    public void listen() throws IOException {
        System.out.println("服务端启动成功!");
        while (true) {                                                               // 轮询访问selector
            selector.select();                                                       // 当注册的事件到达时,方法返回;否则,该方法会一直阻塞,当一个事件到达的时候他会自动监听到
            Iterator<?> ite = this.selector.selectedKeys().iterator();               // 获得selector中选中的项的迭代器,选中的项为注册的事件
            while (ite.hasNext()) {
                SelectionKey key = (SelectionKey) ite.next();                        //获取选中的KEY
                ite.remove();                                                        // 删除已选的key,以防重复处理
                handler(key);
            }
        }
    }
    /**
    * @Description: 处理请求的句柄
    * @Date: 2018/9/12 13:19
    * @author: wgq
    * @version: 1.0
    * @param: 
    */
    public void handler(SelectionKey key) throws IOException {
        if (key.isAcceptable()) {                          // 客户端请求连接事件
            handlerAccept(key);
        } else if (key.isReadable()) {                     // 获得可读的事件
            handelerRead(key);
        }
    }
    /**
    * @Description: 处理连接的请求
    * @Date: 2018/9/12 13:22
    * @author: wgq
    * @version: 1.0
    * @param: 
    */
    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);               // 在和客户端连接成功之后,为了可以接收到客户端的信息,需要给通道设置读的权限。
    }
     /**
     * @Description: 处理读的事件
      *      ByteBuffer:ByteBuffer的读写模式是分开的
      *           创建方式:
      *               1.ByteBuffer buffer=ByteBuffer.allocate(256);
      *               2.ByteBuffer buffer=ByteBuffer.wrap(byteArray);这里的byteArray可以包含了数据,相当于写入了数据到缓冲区
      *            写入数据:
      *               1.ByteBuffer buffer=ByteBuffer.wrap(byteArray)
      *               2.buffer.put(bytes)
      *            清除缓存区:
      *               buffer.clear(); 这个方法实际上也不会改变缓冲区的数据,而只是简单的重置了缓冲区的主要索引值,不必为了每次读写都创建新的缓冲区,那样做会降低性能。
      *               相反,要重用现在的缓冲区,在再次读取之前要清除缓冲区。
      *             读取数据:
      *                 调用buffer.get(bytes);
     * @Date: 2018/9/12 13:20
     * @author: wgq
     * @version: 1.0
     * @param:
     */
    public void handelerRead(SelectionKey key) throws IOException {
        SocketChannel channel = (SocketChannel) key.channel();            // 服务器可读取消息:得到事件发生的Socket通道(其实就是这个请求对应的通道)
        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("好的".getBytes());      //回写数据
            channel.write(outBuffer);                                       // 将消息回送给客户端
        } else {
            System.out.println("客户端关闭");
            key.cancel();
        }
    }
    /**
    * @Description: 启动服务端进行测试
    * @Date: 2018/9/12 13:26
    * @author: wgq
    * @version: 1.0
    * @param: 
    */
    public static void main(String[] args) throws IOException {
        NIOServer server = new NIOServer();
        server.initServer(8000);
        server.listen();
    }
} 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值