BIO & NIO

作者: AC编程 | 来源:发表于2020-08-22 09:04 被阅读0次

一、用单线程来优化不活跃线程较多的情况

BIO等待连接时需要阻塞,等待接收客户端发送数据时也需要阻塞。如果有一个客户端连接了服务端,但一直不发送消息,服务端就一直阻塞等待接收客户端的消息,无法接收其他客户端的连接。因此,如果不用多线程,BIO无法处理并发。

但加入多线程处理并发有一个弊端,如有1000个客户端来连服务端,服务端就需要开启1000个线程来处理客户端的数据,但1000个连接里只有100个连接是活跃连接,另外900个只连接不发送消息,那这900个线程就是浪费。因此,当服务器端不活跃的线程比较多时,要用单线程的方案来优化。

二、代码演示

2.1 IO客户端代码
import java.net.Socket;
import java.util.Scanner;

/**
 * @author Alan Chen
 * @description IO测试
 * @date 2020/8/22
 */
public class Client {

    public static void main(String[] args) throws Exception {
        Socket socket = new Socket("127.0.0.1", 8080);

        //socket.getOutputStream().write("alanchen".getBytes());

        // 体现服务端read是阻塞的,要等客户端发送数据
        Scanner scanner = new Scanner(System.in);
        System.out.println("请输入内容:");
        while (true){
            String next = scanner.next();
            socket.getOutputStream().write(next.getBytes());
        }
    }
}
2.2 BIO 代码
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;

/**
 * @author Alan Chen
 * @description BIO测试
 * @date 2020/8/22
 */
public class BIOServer {

    static byte[] bytes = new byte[1024];

    public static void main(String[] args) throws Exception {

        ServerSocket serverSocket = new ServerSocket();
        serverSocket.bind(new InetSocketAddress(8080));

        while (true){
            System.out.println("等待连接");
            // 阻塞
            Socket socket = serverSocket.accept();
            System.out.println("连接成功");

            /**
             * 如果有客户端连接了,但一直不发送数据,服务端就会阻塞在这里,
             * 无法在处理其他连接,如果要实现并发,则需要开启一个子线程来接收数据
             * 线程代码:略
             */
            System.out.println("等待接收数据");
            //阻塞 读了多少字节
            int read = socket.getInputStream().read(bytes);
            System.out.println("数据接收成功");

            String content = new String(bytes);
            System.out.println(content);
        }
    }
}
2.3 NIO代码
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.List;

/**
 * @author Alan Chen
 * @description NIO测试
 * @date 2020/8/22
 */
public class NIOServer {

    static List<SocketChannel> socketChannelList = new ArrayList<>();
    static ByteBuffer byteBuffer = ByteBuffer.allocateDirect(512);

    public static void main(String[] args) throws Exception {

        ServerSocketChannel serverSocket = ServerSocketChannel.open();
        serverSocket.bind(new InetSocketAddress(8080));
        //设置为非阻塞
        serverSocket.configureBlocking(false);

        while (true){

            SocketChannel socket = serverSocket.accept();

            if(socket==null){
                Thread.sleep(1500);
                System.out.println("没有连接请求");
            }else {
                System.out.println("有连接请求");
                //设置为非阻塞
                socket.configureBlocking(false);
                socketChannelList.add(socket);
            }

            /**
             * 这种轮询的方式效率也很低,比如有1000万个连接,
             * 但只有200万个是活跃的,每次都沦陷另外800万个连接,也是一种资源浪费,
             * 解决方案是用epoll
             */
            for(SocketChannel socketChannel : socketChannelList){
                int k = socketChannel.read(byteBuffer);
                if(k>0){
                    byteBuffer.flip();
                    System.out.println(Charset.forName("utf-8").decode(byteBuffer));
                }
            }

        }
    }
}

相关文章

网友评论

      本文标题:BIO & NIO

      本文链接:https://www.haomeiwen.com/subject/rbxsjktx.html