BIO

作者: 与子笑 | 来源:发表于2021-03-16 17:07 被阅读0次

    在这里使用 java代码,记录 BIO 的理解。要使用 jdk1.4 版本的才能在追踪的时候看出本质。高版本的jdk 内部已经有了优化,会使用poll的方式来执行。Block IO

    linux中使用 strace 命令,可以追踪程序的系统调用。

    追踪示例.png
    import java.io.BufferedReader;
    import java.io.IOException;
    import java.io.InputStream;
    import java.io.InputStreamReader;
    import java.net.ServerSocket;
    import java.net.Socket;
    
    public class SocketBIO {
        public static void main(String[] args) throws IOException {
            ServerSocket server = new ServerSocket(9090, 20);
            System.out.println("服务已开启");
            while (true) {
                Socket client = server.accept();//阻塞1,等待接收连接
                System.out.println("客户端已连上,端口号:" + client.getPort());
                //一旦获取到了一个client,分一个线程出去处理
                new Thread(() -> {
                    InputStream in = null;
                    try {
                        in = client.getInputStream();//获取输入流,字节
                        //将字节转换为字符并读取
                        BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(in));
                        while (true) {
                            String s = bufferedReader.readLine();//阻塞2,获取该线程连接的输入
                            if (null != s) {
                                System.out.println("输入的内容是:" + s);
                            } else {
                                client.close();
                            }
                        }
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }).start();
            }
        }
    }
    

    以上代码执行后,会有两个阻塞,线程一直被挂起,等待连接和输入
    strace追踪后可以发现下图是主线程等待连接的阻塞:

    主线程的阻塞.png
    开启一个socket,返回一个变量3,为3绑定端口号,然后监听,做write系统调用,3这个线程开始等待连接。
    上图中的 2531行中的write函数就是系统调用,参数和上面代码的输出不一致。
    当使用nc命令连接上这个服务后,将会返回一个客户端,进入线程中,主线程继续 accept
    从追踪命令当中可以看到,java当中的新启动一个线程,在linux中,实际上是开启了一个进程。新进程是从主进程中clone出来的。
    新线程的阻塞.png
    返回来个1590进程号。

    继续追踪1590进程号可以发现还有一个recv阻塞了。对应的是代码的这一行bufferedReader.readLine()

    总结.png

    这里的变量5是新线程的client。

    image.png
    1. 因为BIO模式有blocking,所以只能以抛出线城的方式去处理连接,不然在主线程只能接收一个连接。程序员的代码是无法解决这个问题的,因为想要连接多个,必然只能抛出多个线程,因为有阻塞。
    2. 每轮一下,还会涉及到系统调用,accept,clone,recv都是系统调用函数。所以要解决这个问题,只能从内核下手。所以有了后来的NIOnoblock
      以上两点就是BIO的弊端

    相关文章

      网友评论

          本文标题:BIO

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