nio基础笔记(1)

看了挺多次有关于NIO的文章,但是由于项目中用到的少所以不久就忘了,所以在此做个笔记。里面很多内容都是参考的别人的文章还有书籍,希望可以帮到一两个人吧
1、缓冲区Buffer
buffer是一个对象,里面包括了要写入或者读取的数据,面向流的i/o流中所有数据的读写都是直接读或者写到Stream对象中,而NIO是写道buffer中的。所以i/o是面向流的而NIO是面向缓冲区的。
bugger的底层是一个数组,但是其中包含了四种属性
1、capacity
    容量表示缓冲区的大小,其实就是缓冲区域内部数组的大小
2、position
    位置表示缓冲区中当前可读写的位置,当调用get(),put()方法时会自动更新position位置
3、limit
    表示缓冲区中可用元素的大小。当发生读/写转换时会发生改变,当写缓冲区时,limit等于capacity,表示整个缓冲区都可以写,当读缓冲区时,limit代表缓冲区中已有元素的大小,表示读取缓冲区的位置不能超过limit。
4、mark
    mark是备忘位置,可以暂时存储position,以便position改变后可以回到原来位置。
最常用的缓冲区是ByteBuffer,每一种java基本类型(除了Boolean)都对应一种缓冲区。
2、通道Channel
Channel是一个通道,是一个向自来水管一样的*双向*通道,流是单向的只能读或者写,而通道可以读写同时进行。
3、多路复用器Selector
熟练地使用Selector对于NIO十分重要,多路复用器提供已经就绪的任务的能力,简单来说,Selector会不断的轮询注册在其上的Channel,如果某个Channel上面发生读或者写事件,这个Channel就会处于就绪状态,会被Selector轮询出来,然后通过SelectorKey可以获取就绪的Channe集合,然后进行后续的I/O操作。
    一个多路复用器可以同时轮询多个Channel,犹豫JDK使用了epoll()代替传统的select实现,所以它没有最大连接句柄1024/2048的限制,这也就意味着只需要一个线程负责Selector的轮询,就可以接入成千上万的客户端。
package com.dnz.nio;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

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;

/**
 * @author zzz
 * @date 2020/1/3 11:16
 */
public class NioServer {
    private Selector selector;

    public void initServer(int port) throws IOException {
        //获得一个ServerSocketChannel通道
        ServerSocketChannel channel = ServerSocketChannel.open();
        //设置通道为非阻塞
        channel.configureBlocking(false);
        //将该通道对应的ServerSocket绑定到对应port
        channel.socket().bind(new InetSocketAddress(port));
        //获得通道管理器
        this.selector  = Selector.open();
        //绑定通道和通道管理器,并为该通道注册为SelectionKey.OP_ACCEPT事件
        ///当该事件到达时,selector.select()会返回,如果该事件没到达selector.select()会一直阻塞
        channel.register(this.selector,SelectionKey.OP_ACCEPT);
    }

    /**
     * 采用轮询的方式监听selector上是否有需要处理的事件,如果有,则进行处理
     * @throws IOException
     */
    @SuppressWarnings("unchecked")
    public void listen() throws IOException {
        System.out.println("服务端启动成功!");
        // 轮询访问selector
        while (true){
            //当注册的事件到达时,方法返回;否则,该方法会一直阻塞
            selector.select();
            // 获得selector中选中的项的迭代器,选中的项为注册的事件
            Iterator<SelectionKey> iterator = selector.selectedKeys().iterator();
            while (iterator.hasNext()){
                SelectionKey key = iterator.next();
                // 删除已选的key,以防重复处理
                iterator.remove();
                // 客户端请求连接事件
                if (key.isAcceptable()){
                    ServerSocketChannel server = (ServerSocketChannel) key.channel();
                    // 获得和客户端连接的通道
                    SocketChannel channel = server.accept();
                    // 设置成非阻塞
                    channel.configureBlocking(false);


                    //这里编辑给客户端发送的信息
                    channel.write(ByteBuffer.wrap(new String("可以向我发送信息了").getBytes()));
                    //在和客户端连接成功之后,为了可以接收到客户端的信息,需要给通道设置读的权限。
                    channel.register(this.selector, SelectionKey.OP_READ);

                    //获取可读的事件
                }else if (key.isReadable()){
                    read(key);
                }
            }
        }
    }
    /**
     * 处理读取客户端发来的信息和事件
     * */
    public void read(SelectionKey key) throws IOException{
        //服务器可读取消息:得到事件发生的socket通道
        SocketChannel channel = (SocketChannel) key.channel();
        //创建读取的缓冲区
        ByteBuffer buffer = ByteBuffer.allocate(125);
        int read = channel.read(buffer);
        byte[] data = buffer.array();
        String msg = new String(data).trim();
        System.out.println("来自客户端的信息"+msg);
        ByteBuffer buffer1 = ByteBuffer.wrap(msg.getBytes());
        channel.write(buffer1);
    }
    //启动服务端测试
    public static void main(String[] args) throws IOException {
        NioServer server = new NioServer();
        server.initServer(8000);
        server.listen();
    }
}

package com.dnz.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.SocketChannel;
import java.util.Iterator;

/**
 * @author zzz
 * @date 2020/1/3 11:16
 */
public class NioClient {
    private Selector selector;
    /***
     * 获得一个Socket通道,并对该通道做一些初始化的工作
     */
    public void initClient(String ip,int port) throws IOException {
        //获得一个socket通道
        SocketChannel channel = SocketChannel.open();
        //设置非阻塞
        channel.configureBlocking(false);
        //获得通道管理器
        this.selector  = Selector.open();

        // 客户端连接服务器,其实方法执行并没有实现连接,需要在listen()方法中调
        //用channel.finishConnect();才能完成连接
        channel.connect(new InetSocketAddress(ip,port));
        //将通道管理器和该通道绑定,并为该通道注册SelectionKey.OP_CONNECT事件。
        channel.register(selector,SelectionKey.OP_CONNECT);
    }
    /***
     * 采用轮询的方式监听selector上是否有需要处理的事件,如果有,则进行处理
     */
    public void listen() throws IOException {
        //轮询访问selector
        while (true){
            //当注册的事件到达时,方法返回;否则,该方法会一直阻塞
            selector.select();
            //获取selector中选中项的迭代器
            Iterator<SelectionKey> iterator = this.selector.selectedKeys().iterator();
            while (iterator.hasNext()){
                SelectionKey key = iterator.next();
                // 删除已选的key,以防重复处理
                iterator.remove();
                //连接事件发生
                if (key.isConnectable()){
                    SocketChannel channel = (SocketChannel) key.channel();
                    //如果正在连接,则完成连接
                    if (channel.isConnectionPending()){
                        channel.finishConnect();
                    }
                    //设置成非阻塞
                    channel.configureBlocking(false);

                    //在这里可以给服务端发送信息哦
                    channel.write(ByteBuffer.wrap(new String("向服务端发送了一条信息").getBytes()));
                    //在和服务端连接成功之后,为了可以接收到服务端的信息,需要给通道设置读的权限。
                    channel.register(this.selector,SelectionKey.OP_READ);
                }else if (key.isReadable()){
                    read(key);
                }
            }
        }
    }
    public void read(SelectionKey key) throws IOException{
        //服务器可读取消息:得到事件发生的socket通道
        SocketChannel channel = (SocketChannel) key.channel();
        //创建读取的缓冲区
        ByteBuffer buffer = ByteBuffer.allocate(125);
        int read = channel.read(buffer);
        byte[] data = buffer.array();
        String msg = new String(data).trim();
        System.out.println("来自客户端的信息"+msg);
        ByteBuffer buffer1 = ByteBuffer.wrap(msg.getBytes());
        channel.write(buffer1);
    }
    //启动客户端测试
    public static void main(String[] args) throws IOException {
        NioClient client = new NioClient();
        client.initClient("localhost",8000);
        client.listen();
    }
}

转载自:https://www.cnblogs.com/zedosu/p/6666984.html

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值