您当前的位置: 首页 >  linux
  • 0浏览

    0关注

    674博文

    0收益

  • 0浏览

    0点赞

    0打赏

    0留言

私信
关注
热门博文

linux IO模型分享

沙漠一只雕得儿得儿 发布时间:2021-12-03 13:51:11 ,浏览量:0

用户态和内核态

一个完整的 Linux 操作系统体系架构通常由下列几个核心层级组成:

  • Applications:在操作系统上安装并运行的用户态应用程序
  • Shell:支持编程的命令行解析器
  • Libs:操作系统标准库函数
  • System Calls:暴露给用户态的内核态系统调用接口
  • Kernel:操作系统的核心,真正对接硬件平台的软件程序

 

所以,为什么要划分核心态和用户态?简单来说:

  • 禁止用户程序和底层硬件平台直接交互
  • 禁止用户程序直接访问任意内存地址空间
用户态和内核态切换

用户程序除了通过系统调用主动触发模式切换之外,还可能会被动的进行。总的来说模式切换有两种触发手段:

  • (软中断)系统调用:这时用户态进程要传递很多变量或参数值给内核,内核态运行时也要保存用户进程的一些寄存器值和变量等等。所谓的「进程上下文」,可以看作是用户进程传递给内核的这些参数以及内核要保存的那一整套的变量和寄存器值以及运行环境等。

  • (硬中断)外围设备中断:硬件可以通过触发中断信号令内核调用中断处理程序从而进入内核空间。这个过程中,硬件的一些变量和参数也要传递给内核,内核通过这些参数进行中断处理。所谓的「中断上下文」,就是硬件传递过来的这些参数和内核需要保存的当前被中断执行的进程环境。

IO模型如何理解

答案:从代码和system call去理解

BIO

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 TestSocket {

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

        ServerSocket server = new ServerSocket(8090);

        System.out.printf("step1:new ServerSocket(80)");

        while(true){

            final Socket client = server.accept();

            System.out.printf("step2:client\t"+client.getPort());

            new Thread(()->{

                try {

                    InputStream in = client.getInputStream();

                    BufferedReader reader = new BufferedReader(new InputStreamReader(in));

                    while (true){

                        System.out.printf(reader.readLine());

                    }

                }catch (IOException e){

                }

            }).start();

        }

    }

}

socket(AF_INET, SOCK_STREAM, IPPROTO_IP) = 5

fcntl(5, F_GETFL)                       = 0x2 (flags O_RDWR)

fcntl(5, F_SETFL, O_RDWR|O_NONBLOCK)    = 0

setsockopt(5, SOL_SOCKET, SO_REUSEADDR, [1], 4) = 0

..

bind(5, {sa_family=AF_INET, sin_port=htons(8090), sin_addr=inet_addr("0.0.0.0")}, 16) = 0

listen(5, 50)                     

poll([{fd=5, events=POLLIN|POLLERR}], 1, -1

NIO

import java.io.IOException;

import java.net.InetSocketAddress;

import java.nio.ByteBuffer;

import java.nio.channels.ServerSocketChannel;

import java.nio.channels.SocketChannel;

import java.util.LinkedList;

public class TestSocketNIO {

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

        LinkedList socketChannels = new LinkedList();

        ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();

        serverSocketChannel.bind(new InetSocketAddress(8091));

        serverSocketChannel.configureBlocking(false);

        System.out.printf("step1:new ServerSocket(80)");

        while(true){

            SocketChannel client = serverSocketChannel.accept();

            if(client == null){

                System.out.printf("client null");

            }else{

                client.configureBlocking(false);

                int port = client.socket().getPort();

                System.out.printf("client .port :"+port);

                socketChannels.add(client);

            }

            ByteBuffer buff = ByteBuffer.allocateDirect(4096);

            for(SocketChannel socketChannel : socketChannels){

                int num = socketChannel.read(buff);

                if(num>0){

                    buff.flip();

                    byte[] a = new byte[buff.limit()];

                    buff.get(a);

                    String b = new String(a);

                    System.out.printf(socketChannel.socket().getPort()+":"+b);

                    buff.clear();

                }

            }

        }

    }

}

     socket(AF_INET, SOCK_STREAM, IPPROTO_IP) = 4

2711 setsockopt(4, SOL_SOCKET, SO_REUSEADDR, [1], 4) = 0

2712 lseek(3, 64757815, SEEK_SET)            = 64757815

...

2724 bind(4, {sa_family=AF_INET, sin_port=htons(8091), sin_addr=inet_addr("0.0.0.0")}, 16) = 0

2725 listen(4, 50)                           = 0

2726 getsockname(4, {sa_family=AF_INET, sin_port=htons(8091), sin_addr=inet_addr("0.0.0.0")}, [16]) = 0

2727 getsockname(4, {sa_family=AF_INET, sin_port=htons(8091), sin_addr=inet_addr("0.0.0.0")}, [16]) = 0

2728 fcntl(4, F_GETFL)                       = 0x2 (flags O_RDWR)

2729 fcntl(4, F_SETFL, O_RDWR|O_NONBLOCK)    = 0

 ...

     accept(4, 0x2b08f01387e0, 0x2b08ecb87710) = -1 EAGAIN (Resource temporarily unavailable)

2884 accept(4, 0x2b08f013b1e0, 0x2b08ecb87710) = -1 EAGAIN (Resource temporarily unavailable)

2885 accept(4, 0x2b08f0147680, 0x2b08ecb87710) = -1 EAGAIN (Resource temporarily unavailable)

2886 accept(4, 0x2b08f013b1e0, 0x2b08ecb87710) = -1 EAGAIN (Resource temporarily unavailable)

2887 accept(4, 0x2b08f0147680, 0x2b08ecb87710) = -1 EAGAIN (Resource temporarily unavailable)

2888 accept(4, 0x2b08f013b1e0, 0x2b08ecb87710) = -1 EAGAIN (Resource temporarily unavailable)

2889 accept(4, 0x2b08f0147680, 0x2b08ecb87710) = -1 EAGAIN (Resource temporarily unavailable)

select poll epoll

socket(AF_INET, SOCK_STREAM, IPPROTO_IP) = 4

2695 setsockopt(4, SOL_SOCKET, SO_REUSEADDR, [1], 4) = 0

2696 fcntl(4, F_GETFL)                       = 0x2 (flags O_RDWR)

2697 fcntl(4, F_SETFL, O_RDWR|O_NONBLOCK)    = 0

bind(4, {sa_family=AF_INET, sin_port=htons(9000), sin_addr=inet_addr("0.0.0.0")}, 16) = 0

listen(4, 50)                           = 0         

epoll_create(256)                       = 8

2823 epoll_ctl(8, EPOLL_CTL_ADD, 6, {EPOLLIN, {u32=6, u64=17515013522285658118}}) = 0

2824 lseek(3, 52829082, SEEK_SET)            = 52829082

2825 read(3, "PK\3\4\n\0\0\10\0\0\274\205\367N,\270\332\313\v\10\0\0\v\10\0\0!\0\0\0", 30) = 30

2826 lseek(3, 52829145, SEEK_SET)            = 52829145

2827 read(3, "\312\376\272\276\0\0\0004\0M\n\0\23\0005\t\0\22\0006\t\0\22\0007\7\0008\t\0\22\0"..., 2059) = 2059

2828 lseek(3, 31933647, SEEK_SET)            = 31933647

2829 read(3, "PK\3\4\n\0\0\10\0\0\274\205\367ND[\333w\217\3\0\0\217\3\0\0000\0\0\0", 30) = 30

2830 lseek(3, 31933725, SEEK_SET)            = 31933725

2831 read(3, "\312\376\272\276\0\0\0004\0&\n\0\7\0\32\t\0\6\0\33\n\0\6\0\34\7\0\35\n\0\4\0"..., 911) = 911

2832 lseek(3, 31926658, SEEK_SET)            = 31926658

2833 read(3, "PK\3\4\n\0\0\10\0\0\274\205\367N\277`e.\247\7\0\0\247\7\0\0$\0\0\0", 30) = 30

2834 lseek(3, 31926724, SEEK_SET)            = 31926724

2835 read(3, "\312\376\272\276\0\0\0004\0F\n\0\7\0008\t\0\4\0009\n\0\4\0:\7\0;\t\0\4\0"..., 1959) = 1959

2836 write(1, "\347\255\211\345\276\205\344\272\213\344\273\266\345\217\221\347\224\237\343\200\202\343\200\202", 24) = 24

2837 write(1, "\n", 1)                       = 1

2838 lseek(3, 31934636, SEEK_SET)            = 31934636

2839 read(3, "PK\3\4\n\0\0\10\0\0\274\205\367N\3005\227\350\35\3\0\0\35\3\0\0.\0\0\0", 30) = 30

2840 lseek(3, 31934712, SEEK_SET)            = 31934712

2841 read(3, "\312\376\272\276\0\0\0004\0%\t\0\4\0\32\n\0\5\0\33\n\0\30\0\34\7\0\35\7\0\36\7"..., 797) = 797

2842 lseek(3, 66534570, SEEK_SET)            = 66534570

2843 read(3, "PK\3\4\n\0\0\10\0\0\273\205\367N\300\tR\330\242\0\0\0\242\0\0\0\36\0\0\0", 30) = 30

2844 lseek(3, 66534630, SEEK_SET)            = 66534630

2845 read(3, "\312\376\272\276\0\0\0004\0\t\7\0\7\7\0\10\1\0\tinterrupt\1\0\25("..., 162) = 162

2846 epoll_ctl(8, EPOLL_CTL_ADD, 4, {EPOLLIN, {u32=4, u64=289558586198065156}}) = 0

2847 epoll_wait(8,

调用epoll_create时,做了以下事情:

  1. 内核帮我们在epoll文件系统里建了个file结点;
  2. 在内核cache里建了个红黑树用于存储以后epoll_ctl传来的socket;
  3. 建立一个list链表,用于存储准备就绪的事件
关注
打赏
1657159701
查看更多评论
立即登录/注册

微信扫码登录

0.1648s