ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

关于Bio与Nio

2022-09-15 19:01:07  阅读:298  来源: 互联网

标签:Bio java Nio iterator read 关于 new import nio


  程序git:https://gitee.com/juncaoit/netty

  IO模型 IO模型就是说用什么样的通道进行数据的发送和接收,Java共支持3种网络编程IO模式:BIO,NIO,AIO

一:Bio

1.模型

  

 

 

2.服务端

package com.jun.bio;

import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.nio.charset.StandardCharsets;

/**
 * BIO的服务端
 */
public class SocketServer {
    public static void main(String[] args) throws IOException {
        ServerSocket serverSocket = new ServerSocket(9000);
        while (true) {
            // 如果有链接,则进行处理
            Socket clientSocket = serverSocket.accept();
            new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
                        handler(clientSocket);
                    } catch (IOException e) {
                        throw new RuntimeException(e);
                    }
                }
            }).start();
        }
    }

    /**
     * 数据处理
     */
    private static void handler(Socket clientSocket) throws IOException {
        byte[] bytes = new byte[1024];
        int read = clientSocket.getInputStream().read(bytes);
        if (read != -1) {
            System.out.println("接收到的数据是" + new String(bytes, 0, read));
        }
        // 返回客户端一些数据
        clientSocket.getOutputStream().write("收到你的数据了".getBytes(StandardCharsets.UTF_8));
        clientSocket.getOutputStream().flush();
    }
}

 

3.客户端

package com.jun.bio;

import java.io.IOException;
import java.net.Socket;
import java.nio.charset.StandardCharsets;

/**
 * BIO的客户端
 */
public class SocketClient {
    public static void main(String[] args) throws IOException {
        Socket socket = new Socket("127.0.0.1", 9000);
        // 发送数据
        socket.getOutputStream().write("hello 服务端".getBytes(StandardCharsets.UTF_8));
        socket.getOutputStream().flush();
        // 接收返回值
        byte[] bytes = new byte[1024];
        int read = socket.getInputStream().read(bytes);
        if (read != -1) {
            System.out.println("接收到服务端的返回值是" + new String(bytes, 0, read));
        }
        socket.close();
    }
}

 

4.缺点

  1、IO代码里read操作是阻塞操作,如果连接不做数据读写操作会导致线程阻塞,浪费资源   2、如果线程很多,会导致服务器线程太多,压力太大,比如C10K问题   应用场景:   BIO 方式适用于连接数目比较小且固定的架构, 这种方式对服务器资源要求比较高, 但程序简单易理解。

 

二:NIO

1.场景 

  同步非阻塞,服务器实现模式为一个线程可以处理多个请求(连接),客户端发送的连接请求都会注册到多路复用器selector上,多路复用器轮询到连接有IO请求就进行处理,JDK1.4开始引入。   应用场景:   NIO方式适用于连接数目多且连接比较短(轻操作) 的架构, 比如聊天服务器, 弹幕系统, 服务器间通讯,编程比较复杂

 

2.无selector的程序

package com.jun.nio;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.nio.ByteBuffer;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

/**
 * 无select的NIO
 */
public class NoSelectServer {
    // 存客户端链接
    private static List<SocketChannel> clientChannelList = new ArrayList<>();

    public static void main(String[] args) throws IOException {
        ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
        serverSocketChannel.socket().bind(new InetSocketAddress(9000));
        serverSocketChannel.configureBlocking(false);

        while (true) {
            // 如果存在新的链接,则添加到链接队列中
            SocketChannel socketChannel = serverSocketChannel.accept();
            if (socketChannel != null) {
                System.out.println("链接成功");
                socketChannel.configureBlocking(false);
                clientChannelList.add(socketChannel);
            }
            // 循环队列,读取数据
            Iterator<SocketChannel> iterator = clientChannelList.iterator();
            while (iterator.hasNext()) {
                SocketChannel nextChannel = iterator.next();
                ByteBuffer byteBuffer = ByteBuffer.allocate(128);
                int len = nextChannel.read(byteBuffer);
                if (len > 0) {
                    System.out.println("接收到的数据是" + new String(byteBuffer.array()));
                } else if (len == -1) {
                    iterator.remove();
                    System.out.println("客户断开了链接");
                }
            }
        }
    }
}

 

3.使用selector

  

 

 

package com.jun.nio;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
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;
import java.util.Set;

/**
 * 正式的NIO
 */
public class HasSelectorServer {
    public static void main(String[] args) throws IOException {
        // 定义多路复用器
        Selector selector = Selector.open();
        // 服务端链接
        ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
        serverSocketChannel.socket().bind(new InetSocketAddress(9000));
        serverSocketChannel.configureBlocking(false);
        // 将服务端通道注册到selector上
        SelectionKey register = serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);

        // 开始循环是否有
        while (true) {
            selector.select();
            Set<SelectionKey> selectionKeys = selector.selectedKeys();
            Iterator<SelectionKey> iterator = selectionKeys.iterator();
            while (iterator.hasNext()) {
                SelectionKey nextKey = iterator.next();
                // 如果是OP_ACCEPT事件,则进行连接获取和事件注册
                if (nextKey.isAcceptable()) {
                    ServerSocketChannel server = (ServerSocketChannel) nextKey.channel();
                    SocketChannel socketChannel = server.accept();
                    socketChannel.configureBlocking(false);
                    socketChannel.register(selector, SelectionKey.OP_READ);
                    System.out.println("客户端连接成功");
                } else if (nextKey.isReadable()) {
                    SocketChannel client = (SocketChannel) nextKey.channel();
                    ByteBuffer byteBuffer = ByteBuffer.allocateDirect(128);
                    int len = client.read(byteBuffer);
                    if (len > 0) {
                        System.out.println("接收到的数据是" + new String(byteBuffer.array()));
                    } else if (len == -1) {
                        client.close();
                        System.out.println("客户断开了链接");
                    }
                }
                iterator.remove();
            }
        }
    }
}

 

标签:Bio,java,Nio,iterator,read,关于,new,import,nio
来源: https://www.cnblogs.com/juncaoit/p/16697640.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有