IO模型

什么是IO模型

IO分为:网络IO和文件系统IO

image.png

计算机组成

image.png

内核调度不同线程的情况

image.png

1. 网络IO模型

1.1BIO

1.1.1BIO的实现和内核调用

a.BIO程序Java代码

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);
        System.out.println("step1: new ServerSocket(9090)");
        while(true){
            //等待建立Socket连接
            final Socket client = server.accept();//阻塞1
            System.out.println("step2:client\t" + client.getPort());

            new Thread(new Runnable() {
                public void run() {
                    InputStream in = null;
                    try{
                        in = client.getInputStream();
                        BufferedReader reader  = new BufferedReader(new InputStreamReader(in));
                        while(true){
                            //从Socket输出流中读取数据
                            String dataline = reader.readLine();//阻塞2
                            if(null != dataline){
                                System.out.println(dataline);
                            }else {
                                client.close();
                                break;
                            }
                        }
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }).start();
        }
    }
}

b.编译

命令:/usr/java/j2sdk1.4.2_15/bin/javac SocketBIO.java
注意:使用Java1.4进行编译,1.4中的ServerSocket还是用的BIO。

image.png

c.监控程序运行

strace可以用来监控网络IO交互过程中,不同线程的系统调用。
命令:strace -ff -o out /usr/java/j2sdk1.4.2_15/bin/java SocketBIO

image.png

使用jps查看当前主机下运行的Java程序

image.png

d.查看SocketBIO调用过程中,产生的所有系统调用文件

image.png

注意:out.1573是main线程系统调用记录文件,线程号与jps命令查询的SocketBIO的线程号相同。
查看out.1573内容最后

image.png

e.监控out.1573新追加的内容

tail监控指定文件的追加内容,并输出到窗口。
命令:tail -f out.1573

image.png

f.用nc建立连接和变化

image.png
  • 运行程序的变化:
    image.png
  • main线程out.1573变化

    image.png

  • 线程对应系统命令调用文件数量的变化
    原因:client与server新建立一个连接,新的连接是一个单独的线程,需要文件记录。

    image.png

  • 查看新建立连接线程系统调用记录文件的内容

    image.png

g.端口连接情况

Local Address:当前线程的端口
Foreign Address:连接到的端口
netstat:查看当前计算机端口的连接情况
命令: netstat -natp

  • client端口连接
    client使用nc与server建立连接,client端口使用情况如下。


    image.png
  • server端口连接
    Java进程1573监控9090端口,如果有client连接9090端口,交给Java程序处理。


    image.png

h.nc发送数据和变化

image.png
  • 应用程序变化

    image.png

  • out.1636数据变化

    image.png

1.1.2 BIO的缺点和引发的问题

缺点

每一个连接都交给一个线程处理,线程里面接收数据存在阻塞,主线线程中server等待客户端的连接也存在阻塞。

引发的问题

  • 1.很多的线程,资源,创建线程clone,池
  • 2.真正的问题:阻塞
  • 3.cpu执行被中断后,这些线程有可能获取到执行权,单线程中存在阻塞,效率低,频繁切换线程浪费CPU资源。

1.1.3 BIO的整体流程图

image.png

1.2 NIO

1.2.1 BIO和NIO的不同点

image.png

1.2.2 NIO的整体流程图

image.png

1.2.3 NIO代码实现

import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.LinkedList;

public class SocketNIO {

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

        LinkedList<SocketChannel> clients = new LinkedList<>();

        ServerSocketChannel ss = ServerSocketChannel.open();//服务器开启监听,接受客户端
        ss.bind(new InetSocketAddress(9090));
        ss.configureBlocking(false);//中点  OS  NONBLOCKING   //只让接受客户端
        //fcntl(6, F_SETFL, O_RDWR|O_NONBLOCK)    = 0

        while(true){     //接受客户端的连接

            Thread.sleep(1000);
            SocketChannel client = ss.accept();//不会阻塞? -1 NULL
            /**
             * accept 调用内核了:1.没有客户端连接进来,返回值?在BIO的时候一直卡着,但是在NIO,不卡着,返回-1
             * 如果来客户端的连接,accept返回的是这个客户端的fd  5. client  object
             * NONBLOCKING 就是代码能往下走了,只不过有不同的情况
             */

            if(client == null){

            }else{
                client.configureBlocking(false);//重点 socket(服务端的listen socket 连接请求三次握手后,
                int port = client.socket().getPort();
                System.out.println("client..port:" + port);
                clients.add(client);
            }

            ByteBuffer buffer = ByteBuffer.allocate(4096);      //可以在堆里,堆外

            /**
             * 遍历已经连接进来的客户端能不能读写数据
             */
            for(SocketChannel c : clients){     //串行化,   多线程
                int num = c.read(buffer);       // > 0 , -1,  0 不会堵塞
                if(num > 0){
                    buffer.flip();
                    byte[] aaa = new byte[buffer.limit()];
                    buffer.get(aaa);

                    String b = new String(aaa);
                    System.out.println(c.socket().getPort() + " : " + b);
                    buffer.clear();
                }
            }

        }
    }
}
  • 监控Socket连接情况
    命令: strace -ff -o out java SocketNIO

    image.png

  • 查看主函数所在配置文件


    image.png

    image.png
  • nc连接


    image.png
  • socket端口连接情况


    image.png
  • 主线程文件变化


    image.png
  • 客户端


    image.png

1.2.4 NIO的实现

注意:NIO并不是Java代码实现,而是内核实现。Java中调用了内核实现。
命令: man 2 socket
查看内核中关于socket的实现和相关操作

image.png

1.3 select,poll

1.3.1 select,poll图解

  • BIO


    image.png
  • NIO


    image.png
  • select,poll


    image.png

1.3.2 select,poll的流程

  • 1.在server的main线程中,缓存了所有的客户端连接,在NIO中是逐个遍历客户端,如果客户端有发送数据,则server处理客户端发送的数据。
  • 2.在select,poll中不需逐个遍历客户端。将客户端作为参数传递给“电话机”,“电话机”会将客户端发送数据连接返回给server,server遍历这些发送数据的客户端,减少系统调用的时间浪费。
  • 3.多路复用器。

1.3.3 select,poll的实现

命令:man 2 select
man 2 poll
查看函数的实现。


image.png

image.png

select,poll都不是Java来实现的,都是由c语言来实现的。

1.3.4 select,poll解决的问题

server不需要每次都遍历所有的客户端连接。

1.4 epoll

1.4.1 epoll图解

image.png

1.4.2 epoll原理

epoll只是在poll的基础上,添加了一个记事本,记事本可以记录当前所有连接,不需要每次都将所有的客户端连接作为参数传递过去。

1.4.3 epoll实现

image.png
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,542评论 6 504
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,822评论 3 394
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 163,912评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,449评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,500评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,370评论 1 302
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,193评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,074评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,505评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,722评论 3 335
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,841评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,569评论 5 345
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,168评论 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,783评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,918评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,962评论 2 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,781评论 2 354

推荐阅读更多精彩内容