IO

  • java网络编程
  • 阻塞IO
  • NIO

1. java网络编程

  • 基础知识
    1.ip地址和端口号
    2.tcp/udp协议
    3.URL
    4.InetAddress
    public void test() throws IOException{
        //使用URL读取网页
        //创建一个URL实例
        URL url=new URL("http://www.baidu.com");
        //通过openstream方法虎丘资源字节输入流
        InputStream is=url.openStream();
         //字节输入转为字符,不指定编码,中文可能乱码
        InputStreamReader isr=new InputStreamReader(is,"UTF-8"); 
         //字符输入假如缓存,提高读写效率
        BufferedReader br=new BufferedReader(isr);
        String data = br.readLine();
        while (data != null) {
            System.out.println(data);//输出
            data=br.readLine();
        }
        br.close();
        isr.close();
        is.close();
    }
  • socket
    1.创建socket实例
    2.客户端链接
    3.服务端链接
    4.总结

客户端代码

    public void socket() throws IOException {
        //1.创建客户端socket,指定服务器地址和端口
        Socket socket = new Socket("localhost", 10086);
        //2.获取输出流
        OutputStream os = socket.getOutputStream();
        PrintWriter pw = new PrintWriter(os);  //输出包装成打印流
        pw.flush();
        socket.shutdownOutput();

        //3.获取输入流,读取服务器响应数据
        InputStream is = socket.getInputStream();
        BufferedReader br = new BufferedReader(new InputStreamReader(is));
        String info = null;
        if ((info = br.readLine()) != null) {
            System.out.println("我是客户端,服务器端说" + info);
        }
        //4.关闭资源
        br.close();
        is.close();
        pw.close();
        os.close();
        socket.close();
    }

服务端代码

    /**
     * 基于TCP协议的socket通信,实现用户登录,服务端
     */
    public void  serverSocket() throws IOException{
        //1.创建一个服务器端的socket,即ServerSocket,指定绑定端口,监听端口
        ServerSocket serverSocket=new ServerSocket(10086);
        //2.调用accept 开始监听,等待客户端连接
        Socket socket=serverSocket.accept();
        //3.获取输入流,读取客户端
        InputStream is = socket.getInputStream();
        BufferedReader br = new BufferedReader(new InputStreamReader(is));
        String info = null;
        if ((info = br.readLine()) != null) {
            System.out.println("我是服务器,客户端说" + info);
        }
        socket.shutdownOutput();//关闭输入流

        //4.获取输出流,响应客户端信息
        OutputStream os = socket.getOutputStream();
        PrintWriter pw = new PrintWriter(os);  //输出包装成打印流
        pw.write("欢迎您......");
        pw.flush();

        //5.关闭资源
        pw.close();
        os.close();
        br.close();
        is.close();
        socket.close();
        serverSocket.close();

    }
总结
  1. 创建ServerSocket和Socket
    serverSocket.accept()
  2. 打开连接到Socket的输入输出流
    socket.openInputStream()
  3. 按照协议对Socket进行读写
    包装流输入输出
  4. 关闭输入,输出流,关闭socket
    serverSocket还要关闭socket

2. 阻塞IO

java的I/O接口

  1. 基于字节
    InputStream或OutputStream
  2. 基于字符
    Writer和Reader
  3. 基于磁盘
    File
  4. 基于网络
    Socket

一直是阻塞的,会等到数据到来时才返回
eg:serverSocket.accept()一直等到有客户端socket连接时启用一个线程

总结
1.BIO数据在写入OutputStream或者从InputStream读取时都有阻塞
2.当前一些需要大量HTTP长连接

IO_第1张图片

NIO

基本原理

  1. 是事件到来时,才执行,不是像BIO那样始终监视
  2. 有线程间通信方式,通过wait/notify方法,保证每次上下文切换都是有意义的,提高CPU的效率
  3. 有一个线程处理所有的IO事件
IO_第2张图片

通信模型
双向通道

IO_第3张图片

代码

客户端

    public Selector mSelector;

    public void initClient(String ip, int port) throws IOException {
        //1.获取一个Socket通道
        SocketChannel channel = SocketChannel.open();
        //2.设置通道为非阻塞
        channel.configureBlocking(false);
        //3.获得一个通道管理器
        mSelector = Selector.open();

        //客户端连接服务器,方法执行并没有实现连接,需要在listen方法中调用
        //用channel.finisConnection 才能完成连接
        channel.connect(new InetSocketAddress(ip, port));
        //将通道管理器和通道绑定,并为该通道注册selecionKey.OP_CONNECT事件
        channel.register(mSelector, SelectionKey.OP_CONNECT);
    }

    /**
     * 采用轮询的方式监听selector上是否有需要处理的事件,有则进行处理
     */
    public void listen() throws IOException {
        //轮询方式
        while (true) {
            mSelector.select();
            //获得selector中选中的迭代器
            Iterator iterator = mSelector.selectedKeys().iterator();
            while (iterator.hasNext()) {
                SelectionKey key = (SelectionKey) 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(mSelector,SelectionKey.OP_READ);
                    //
                    //获得可读事件
                }else if(key.isReadable()){
                    read(key);
                }
            }
        }
    }

    private void read(SelectionKey key) {

    }

服务器端

 //通道管理器
    private Selector mSelector;

    /**
     * 获得一个ServerSocket通道,并对改通道做一些初始化操作
     */

    public void initServer(int port) throws IOException{
        //获得一个ServerSocket通道
        ServerSocketChannel channel=ServerSocketChannel.open();
        //2.设置通道为非阻塞
        channel.configureBlocking(false);
        //将通道对应的serverSocket绑定到port端口
        channel.socket().bind(new InetSocketAddress(port));
        //3.获得一个通道管理器
        mSelector = Selector.open();


        //将通道管理器和通道绑定,并为该通道注册selecionKey.OP_ACCEPT事件
        //注册该时间后,当事件到达时,selector.select会反悔,
        //如果该事件没到达selector.select会一直阻塞
        channel.register(mSelector, SelectionKey.OP_ACCEPT);
    }

    /**
     * 采用轮询的方式监听selector上是否有需要处理的事件
     */
    /**
     * 采用轮询的方式监听selector上是否有需要处理的事件,有则进行处理
     */
    public void listen() throws IOException {
        System.out.println("服务器端启动成功");
        //轮询方式
        while (true) {
            mSelector.select();
            //获得selector中选中的迭代器
            Iterator iterator = mSelector.selectedKeys().iterator();
            while (iterator.hasNext()) {
                SelectionKey key = (SelectionKey) 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(mSelector,SelectionKey.OP_READ);
                    //
                    //获得可读事件
                }else if(key.isReadable()){
                    read(key);
                }
            }
        }
    }

    private void read(SelectionKey key) {

    }

你可能感兴趣的