目录

深入浅出IO模型(一):BIO

预备阶段

首先,我们编写一个简单的socket程序

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 jooks {
    public static void main(String[] args) throws IOException {
        ServerSocket socket = new ServerSocket(8090); //主动套接字 => 监听套接字
        System.out.println("new a socket on port:8090");
        while (true) {
            Socket client = socket.accept(); //监听套接字 => 已连接套接字
            System.out.println("client\t" + client.getPort());
            new Thread(() -> {
                try {
                    InputStream is = client.getInputStream();
                    BufferedReader reader = new BufferedReader(new InputStreamReader(is));
                    while (true) {
                        System.out.println(reader.readLine());  //recv
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }).start();
        }
    }
}

通过strace -ff -o ./ooxx java jooks抓取运行这个java程序产生的系统调用

然后可以在当前文件目录下发现很多文件

https://img.jooks.cn/img/20210316155752.png

这些ooxx.*就代表一个个线程被记录的系统调用。(启动jvm就会产生很多线程)

这时候通过grep 'port:8090' ./*查找我们java程序中写的输出。

https://img.jooks.cn/img/20210316155829.png

发现在1865中。打开ooxx.1865文件发现如下内容。

https://img.jooks.cn/img/20210316160023.png

通过jps命令查看java进程的id号。

https://img.jooks.cn/img/20210316160232.png

然后进入/proc/1864/fd

https://img.jooks.cn/img/20210316160335.png

发现这里有如下文件,0-5分别对应了ooxx文件中的数字(文件描述符)。其中最后两个是socket。

开始通信

这时通过nc 127.0.0.1 8090与java进程产生通信

https://img.jooks.cn/img/20210316155055.png

https://img.jooks.cn/img/20210316160511.png

这时候,多了一个ooxx文件

https://img.jooks.cn/img/20210316160615.png

等会儿再进去,先去看看ooxx.1865线程发生了什么变化

https://img.jooks.cn/img/20210316160957.png

可以看到这里accept了127.0.0.1:42556的连接。同时,/proc/1864/fd也发生了变化

https://img.jooks.cn/img/20210316161211.png

发现这里多了一个叫6的socket,这就是ooxx.1865中看到的accpet返回的。

我们再看看新产生的ooxx.1906。

https://img.jooks.cn/img/20210316162006.png

发现这里有个recvfrom,然后还write了我们nc发送的数据,这时候nc再发一行试试。

https://img.jooks.cn/img/20210316162117.png

至此实操结束。

做个小总结

刚刚发生了什么,如下图所示。

创建主动套接字4

https://img.jooks.cn/img/20210316163120.png

根据4创建监听套接字5

https://img.jooks.cn/img/20210316163208.png

绑定8090端口、设置监听

https://img.jooks.cn/img/20210316163645.png

调用poll() ===========> 客户端发送连接,服务端accpet(),然后返回已连接套接字6

https://img.jooks.cn/img/20210316163726.png

从6,recv(阻塞式)

https://img.jooks.cn/img/20210316163846.png


画个图

https://img.jooks.cn/img/20210316170726.png

可以发现,这种模式处理多个客户端请求时,是产生多个线程来应付的,产生的系统调用也很多,不是一个好办法。


以上就是bio模型