FD与Socket与IO

Socket

在这里插入图片描述

建立Socket通信

在这里插入图片描述

  • 通过建立Socket通信的流程图可以知道会有两个地方容易发生阻塞,即建立连接的时候以及客户端和服务器端相互传输数据的时候
  • EOF:是一个计算机术语,为End Of File的缩写,在操作系统中表示资料源无更多的资料可读取。资料源通常称为档案或串流。通常在文本的最后存在此字符表示资料结束

系统相关

FD:文件描述符

在这里插入图片描述

  • Linux 服务端创建一个Socket,同时也会创建一个FD指向代表该Socket的文件

用户态、内核态

在这里插入图片描述

  • 用户态和内核态:当进程运行在用户空间时,就处于用户态运行,否则处于内核态
  • 用户空间只能执行一些相对安全的CPU指令
  • 内核空间用于执行一些特权CPU指令
  • 用户态与内核态的转化:比如涉及到一些Socket操作,都是在内核空间中完成的,用户空间主要通过内核空间提供的诸如read、write的系统调用函数调用内核空间完成Socket操作。比如执行read系统调用函数,此时就会将涉及到的fd内容从用户空间拷贝到内核空间、进程从用户空间切换到内核空间,这就是用户态切换为内核态。当内核空间完成socket操作后,将数据会先从网卡拷贝到内核空间(Socket缓冲区),再作为返回值从内核空间拷贝到用户空间、进程也会从内核空间切换到用户空间,这就是内核态切换为用户态

Unix 网络编程中的五种IO模型

在这里插入图片描述

阻塞与非阻塞,同步与异步

  • 阻塞:用户进程/线程,调用内核进程,不能马上得到结果,而导致用户进程进入等待队列
  • 非阻塞:用户进程,调用内核进程,能马上得到一个结果,用户进程继续运行
  • 同步:用户进程,调用内核进程,用户进程等待调用结果
  • 异步:用户进程,调用内核进程,用户进程不等待调用结果
  • 阻塞、非阻塞 都是同步的,因为这两种调用方式都需要等待调用结果

BIO

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

NIO

在这里插入图片描述
在这里插入图片描述

IO多路复用

在这里插入图片描述
在这里插入图片描述

  • select、poll、epoll 的执行都是在内核中执行的,用户进程只是发起对这三个函数的调用

select

在这里插入图片描述

  • nfds:告诉内核空间三个文件描述符集合中最大的文件描述符最大值,明确告知内核空间需要检查的fd有多少
  • timeval:超时时间
    • 如果为0,则表示内核空间不等待,直接判断是否有正常的数值的fd并返回
    • 如果超时时间设置为-1,则表示需要内核空间一直等待,直到有正常数值的fd才返回
      在这里插入图片描述
  • 用户空间调用select函数,首先会将所有需要监听的fd集合从用户空间拷贝一份到内核空间,然后内核空间轮询所有fd集合中所有fd,返回就绪的fd数量。但是用户空间并不知晓fd集合中哪个fd是就绪的,所以此时用户空间还需要检查fd集合中所有fd,检查到以后对就绪的fd进行后续处理,然后发起下一次的select调用
    在这里插入图片描述
  • 如果内核进程轮询所有fd均没有已经就绪的,此时内核进程会有两种选择:
    • 1.继续下一次轮询遍历,直到有准备就绪的fd,这种办法会占用大量的CPU
    • 2.让该用户进程阻塞(目前的做法),直到网卡接收到数据包并将该数包据通过DMA的方式写入到指定的内存中,然后会通过中断信号告诉CPU,CPU响应中断请求调用中断的处理程序进行后续处理:
      • 首先根据数据包的IP和端口号找到对应的socket,然后将该数据保存到该socket的接收队列
      • 然后检查该socket对应的等待队列中是否有阻塞进程等待,如果有的话则会唤醒该进程,然后内核空间会检查这个fd集合,返回准备就绪的fd数量到用户空间结束select的阻塞
fd_set fd集合

在这里插入图片描述

  • 内核进程通过 select 函数仅返回了准备就绪的fd数量,需要用户进程自己遍历fd集合,所以就需要改变fd集合中对应监听的fd的状态告知用户空间放到集合中哪些fd就绪了
  • 如上图所示,fd_set为一个16长度的long类型数组,是通过 bitmap 来表示的,最多有1024位,即最多一次对1024个fd进行监听,调用select函数前后表达不同的含义,调用select前fd集合的位图可以看出来本次监听的fd是1和3,调用select函数后可以得知只有为3的fd准备就绪了
select总结

在这里插入图片描述

  • 1024的限制可以被更该,但是需要重新编译Linux系统
  • 每次调用select函数前后,还是需要用户态与内核态的切换
  • fd集合在select函数调用前后表示的含义不同,所以每次调用select函数都需要将fd集合重置成我们需要监听的fd
  • 用户进程还是会阻塞,只是阻塞都集中在一个对象上–>select 函数

poll

在这里插入图片描述

  • poll新定义了一种数据结构pollfd,通过pollfd中的events和revents判断fd是否准备就绪,而且需要监听的fd集合在用户空间时是由pollfd组成的数组,但是拷贝到内核空间后是由pollfd组成的链表
poll总结

在这里插入图片描述

  • 与select相比,通过这种新定义的数据结构作为fd集合这样就不受限于1024位,也不再是同一个bit位表示fd是否就绪,也不用每次函数调用前都需要重置fd集合,然后与select就没有其他差别(用户进程还是会阻塞,只是阻塞都集中在一个对象上–>poll 函数)

epoll

epoll_create、epoll_ctl

在这里插入图片描述

  • epoll_ctl函数主要是操作epoll_create生成的epoll文件描述符所指向的在内核中开辟的空间
  • 操作种类(op)有三种:
    • 1.向这个开辟的内核空间中新增fd
    • 2.从这个开辟的内核空间中删除fd
    • 3.更新这个开辟的内核空间中的fd
  • epoll_ctl函数对这个开辟的内核空间中的fd具体的操作类型:1.监听读、2.监听写
  • epoll_wait

在这里插入图片描述

  • epoll_wait函数和select/poll函数类似,都是用于给用户进程调用内核进程完成对fd的监听,并得到监听的结果
  • maxevents表示:用户空间调用该函数时,如果内核空间返回100个就绪的fd,但是用户空间最多只能处理其中的n个,这个n就是用户空间此次需要监听并得到结果的最大fd数
epoll流程
调用epoll_create

在这里插入图片描述

  • rbr:将用户空间指明需要监听的fd通过红黑树的形式存储
  • rdllist:存储来自rbr中已经就绪的fd
  • wq:如果用户进程指明需要监听的所有fd均没有准备就绪,此时该用户进程会阻塞,存放到这个等待队列,等待唤醒
调用epoll_ctl

在这里插入图片描述

  • 此时用户进程调用epoll_ctl函数,将需要监听的fd作为参数,告诉内核进程将该fd添加到rbr指向的红黑树,并且会把这个fd封装成数据结构epitem
  • epitem中除了存储需要监听的单个fd以外还有其他属性,rbn指明了该fd在红黑树中的位置、ffd指明了fd就绪时需要存放的rdllist、ep指明了该fd属于具体的哪个eventpoll对象(epoll文件)、pwqlist是一个等待队列指明了该fd就绪时需要调用的ep_poll_callback回调函数,唤醒wq中对应的用户进程
调用epoll_wait

在这里插入图片描述

  • 调用epoll_wait函数,检查eventpoll对象的就绪队列中是否有就绪的fd,如果没有就绪的fd,则此时用户进程进入阻塞,存放到wq中等待唤醒。否则返回就绪的一个或多个fd,数量不大于maxevents
    在这里插入图片描述
  • 被唤醒的流程:网卡接收到数据包并将该数包据通过DMA的方式写入到指定的内存中,然后会通过中断信号告诉CPU,CPU响应中断请求调用中断的处理程序进行后续处理:首先根据数据包的IP和端口号找到对应的socket,然后将该数据保存到该socket的接收队列,然后通过对应的epitem中的pwqlist中的回调函数将epitem添加到就绪队列rdllist,最后唤醒对应的用户进程继续执行epoll_wait函数在这里插入图片描述
epoll总结

在这里插入图片描述

  • 用户进程想要监听的fd,不再是直接从用户空间拷贝到内核空间,而是通过调用epoll_ctl函数,直接让内核空间将该fd添加并维护到eventpoll对象的rbr指向的红黑树中
水平触发与边缘触发

在这里插入图片描述

  • 水平触发牺牲了一定性能但更注重安全
  • 边缘触发牺牲了安全性更注重性能

总结

在这里插入图片描述

  • 5
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
要配置FD.io VPP与DPDK,您可以按照以下步骤进行操作: 1. 安装DPDK:首先,确保您的系统符合DPDK的要求,并按照DPDK官方文档中的说明进行安装。您可以从DPDK官方网站上下载DPDK的源代码,并按照提供的说明进行编译和安装。 2. 配置DPDK环境变量:设置DPDK环境变量,包括`RTE_SDK`和`RTE_TARGET`。`RTE_SDK`指向DPDK源代码目录的路径,`RTE_TARGET`指定您要构建的目标平台。例如,在bash shell中,您可以使用以下命令设置环境变量: ``` export RTE_SDK=/path/to/dpdk export RTE_TARGET=<target> ``` 3. 配置VPP:安装FD.io VPP并启动VPP进程。您可以从FD.io VPP官方网站上获取安装说明,并根据指南进行安装。在启动VPP之前,确保您已正确配置了DPDK。 4. 配置VPP与DPDK集成:编辑VPP的运行时配置文件,通常是位于`/etc/vpp/startup.conf`。将DPDK驱动程序与VPP绑定,指定所需的物理接口和CPU核心。 例如,要将DPDK绑定到VPP并配置两个物理接口(例如eth0和eth1),可以在配置文件中添加以下内容: ``` dpdk { dev <DPDK_DEVICE_NAME> { num-rx-queues <NUM_RX_QUEUES> num-tx-queues <NUM_TX_QUEUES> socket-mem <SOCKET_MEM> } } interface <INTERFACE_NAME> { dpdk <DPDK_DEVICE_NAME> } ``` 在上述配置中,您需要将`<DPDK_DEVICE_NAME>`替换为DPDK设备名称(例如`0000:00:00.0`),`<NUM_RX_QUEUES>`和`<NUM_TX_QUEUES>`分别是接收和发送队列的数量,`<SOCKET_MEM>`是用于DPDK内存的分配。 5. 启动VPP:使用VPP启动命令启动VPP进程,例如: ``` sudo vpp -c /etc/vpp/startup.conf ``` 在启动VPP后,它将根据配置文件中的设置与DPDK集成。 请注意,这只是简单的配置示例,您可能需要根据您的特定需求进行更详细的配置。您可以参考FD.io VPP和DPDK的官方文档以获取更多详细信息和配置选项。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值