IO积累02

爷,独闯天下 提交于 2020-10-08 00:59:07

BIO模型
获取socket连接返回一个文件描述符fd3,bind(fd3,8090)fd3绑定端口,listen(fd3)fd3监听端口【阻塞状态】
accept(fd3,client)获取客户端连接返回文件描述符fd5 【阻塞状态】

public static void main(String[] args) throws Exception {
        ServerSocket server = new ServerSocket(9090,20);

        System.out.println("step1: new ServerSocket(9090) ");

        while (true) {
            Socket client = server.accept();  //阻塞1
            System.out.println("step2:client\t" + client.getPort());

            new Thread(() -> {
                InputStream in = null;
                try {
                    in = client.getInputStream();
                    BufferedReader reader = new BufferedReader(new InputStreamReader(in));
                    while(true){
                        String dataline = reader.readLine(); //阻塞2

                        if(null != dataline){
                        System.out.println(dataline);
                        }else{
                            client.close();
                            break;
                        }
                    }
                    System.out.println("客户端断开");

                } catch (IOException e) {
                    e.printStackTrace();
                }


            }).start();

        }
    }


NIO模型
socket得到文件描述符fd3,fd3绑定端口监听该端口,设置fd3为非阻塞的,获取客户端不阻塞,所以效率高
当有客户端连接进来以后,返回文件描述符fd4 【非阻塞状态】

 LinkedList<SocketChannel> clients = new LinkedList<>();

        ServerSocketChannel ss = ServerSocketChannel.open();  //服务端开启监听:接受客户端
        ss.bind(new InetSocketAddress(9090));
        ss.configureBlocking(false); //重点  OS  NONBLOCKING!!!  //只让接受客户端  不阻塞

//        ss.setOption(StandardSocketOptions.TCP_NODELAY, false);
//        StandardSocketOptions.TCP_NODELAY
//        StandardSocketOptions.SO_KEEPALIVE
//        StandardSocketOptions.SO_LINGER
//        StandardSocketOptions.SO_RCVBUF
//        StandardSocketOptions.SO_SNDBUF
//        StandardSocketOptions.SO_REUSEADDR

        while (true) {
            //接受客户端的连接
            Thread.sleep(1000);
            SocketChannel client = ss.accept(); //不会阻塞?  -1 NULL
            //accept  调用内核了:1,没有客户端连接进来,返回值?在BIO 的时候一直卡着,但是在NIO ,不卡着,返回-1,NULL
            //如果来客户端的连接,accept 返回的是这个客户端的fd  5,client  object
            //NONBLOCKING 就是代码能往下走了,只不过有不同的情况

            if (client == null) {
                System.out.println("null.....");
            } else {
                client.configureBlocking(false); //重点  socket(服务端的listen socket<连接请求三次握手后,往我这里扔,我去通过accept 得到  连接的socket>,连接socket<连接后的数据读写使用的> )
                int port = client.socket().getPort();
                System.out.println("client...port: " + port);
                clients.add(client);
            }

            ByteBuffer buffer = ByteBuffer.allocateDirect(4096);  //可以在堆里   堆外

            //遍历已经链接进来的客户端能不能读写数据
            for (SocketChannel c : clients) {   //串行化!!!!  多线程!!
                int num = c.read(buffer);  // >0  -1  0   //不会阻塞
                if (num > 0) {
                    buffer.flip();
                    byte[] aaa = new byte[buffer.limit()];
                    buffer.get(aaa);

                    String b = new String(aaa);
                    System.out.println(c.socket().getPort() + " : " + b);
                    buffer.clear();
                }


            }
        }
    }
    
多路复用器,select、poll、epoll
不是用多路复用器,需要遍历全部的客户端,查看是否有诗句传入【同步阻塞】
select、poll:传入所有的fd,操作系统遍历传入的文件描述符,返回有状态的文件描述符,在有程序进行遍历处理【同步非阻塞】
epoll:创建servicesocket连接得到连接的文件描述符fd4,fd4绑定端口并监听端口,调用epoll_create,在内存开辟空间返回文件描述符fd7,
使用epoll_ctl 把fd4存入fd7所表示的内存空间,当有客户端连接时,得到文件描述符fd5,会把fd5也存储到fd7所表示的内存空间中,如果文件描述符状态发生改变,会把该文件描述符存入
另一块内存空间以链表的形式进行存储,服务端调用epoll_wait,直接查询链表,省略了操作系统遍历的过程,所以效率比较高,select、poll是把传入的文件描述符遍历最后返回状态改变的,
epoll进行了优化,把遍历文件描述符的过程省略了,在客户端连接的过程中进行处理,把状态改变的文件描述符知己存入到链表中【同步非阻塞】

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!