select、poll、epoll的原理与区别

2023-05-16

文章目录

  • 前言
  • 同步I/O
  • 异步I/O
  • 阻塞I/O
  • 非阻塞I/O
  • 多路复用I/O
    • select
      • select整个处理过程如下
      • select函数原型:
      • select的缺点
    • poll
    • epoll
      • epoll的原理
      • epoll的操作模式
      • epoll的函数
        • epoll_create()
        • epoll_ctl()
        • epoll_wait()
      • epoll为什么更高效

前言

本文讨论的开发环境是 Linux 网络io

同步I/O

在操作系统中,程序运行的空间分为内核空间和用户空间,用户空间所有对io操作的代码(如文件的读写、socket的收发等)都会通过系统调用进入内核空间完成实际的操作。

而且我们都知道CPU的速度远远快于硬盘、网络等I/O。在一个线程中,CPU执行代码的速度极快,然而,一旦遇到I/O操作,如读写文件、发送网络数据时,就需要等待 I/O 操作完成,才能继续进行下一步操作,这种情况称为同步 I/O。

在某个应用程序运行时,假设需要读写某个文件,此时就发生了 I/O 操作,在I/O操作的过程中,系统会将当前线程挂起,而其他需要CPU执行的代码就无法被当前线程执行了,这就是同步I/O操作,因为一个IO操作就阻塞了当前线程,导致其他代码无法执行,所以我们可以使用多线程或者多进程来并发执行代码,当某个线程/进程被挂起后,不会影响其他线程或进程。

多线程和多进程虽然解决了这种并发的问题,但是系统不能无上限地增加线程/进程。由于系统切换线程/进程的开销也很大,所以,一旦线程/进程数量过多,CPU的时间就花在线程/进程切换上了,真正运行代码的时间就少了,这样子的结果也导致系统性能严重下降。

多线程和多进程只是解决这一问题的一种方法,另一种解决I/O问题的方法是异步I/O,当然还有其他解决的方法。

异步I/O

当程序需要对I/O进行操作时,它只发出I/O操作的指令,并不等待I/O操作的结果,然后就去执行其他代码了。一段时间后,当I/O返回结果时,再通知CPU进行处理。这样子用户空间中的程序不需要等待内核空间中的 I/O 完成实际操作,就可执行其他任务,提高CPU的利用率。

简单来说就是,用户不需要等待内核完成实际对io的读写操作就直接返回了。

阻塞I/O

在linux中,默认情况下所有的socket都是阻塞的,一个典型的读操作流程大概是这样:

用户空间 内核空间 调用read()/readform()等函数 进程进入阻塞状态 如果当前没有数据, 则进入阻塞状态, 直到有数据才返回 返回读取到的数据 用户空间 内核空间

当用户进程调用了read()/recvfrom()等系统调用函数,它会进入内核空间中,当这个网络I/O没有数据的时候,内核就要等待数据的到来,而在用户进程这边,整个进程会被阻塞,直到内核空间返回数据。当内核空间的数据准备好了,它就会将数据从内核空间中拷贝到用户空间,此时用户进程才解除阻塞的的状态,重新运行起来。

所以,阻塞I/O的特点就是在IO执行的两个阶段(用户空间与内核空间)都被阻塞了。

非阻塞I/O

linux下,可以通过设置socket使其变为非阻塞模式,这种情况下,当内核空间并无数据的时候,它会马上返回结果而不会阻塞,此时用户进程可以根据这个结果自由配置,比如继续请求数据,或者不再继续请求。当对一个非阻塞socket执行读操作时,流程是这个样子:

用户空间 内核空间 调用read()/recvfrom()等函数 进程不阻塞 没有数据,立即返回 调用read()/recvfrom()等函数 进程不阻塞 没有数据,立即返回 调用read()/recvfrom()等函数 进程不阻塞 没有数据,立即返回 调用read()/recvfrom()等函数 将数据从内核空间 拷贝到用户空间 返回读取到的数据 用户空间 内核空间

当用户进程调用read()/recvfrom()等系统调用函数时,如果内核空间中的数据还没有准备好,那么它并不会阻塞用户进程,而是立刻返回一个error。

对于应用进程来说,它发起一个read()操作后,并不需要等待,而是马上就得到了一个结果。用户进程判断结果是一个error时,它就知道内核中的数据还没有准备好,那么它可以再次调用read()/recvfrom()等函数。

当内核空间的数据准备好了,它就会将数据从内核空间中拷贝到用户空间,此时用户进程也就得到了数据。

所以,非阻塞I/O的特点是用户进程需要不断的主动询问内核空间的数据准备好了没有。

多路复用I/O

多路复用I/O就是我们说的select,poll,epoll等操作,复用的好处就在于单个进程就可以同时处理多个网络连接的I/O,能实现这种功能的原理就是select、poll、epoll等函数会不断的轮询它们所负责的所有socket,当某个socket有数据到达了,就通知用户进程。

一般来说I/O复用多用于以下情况:

  1. 当客户处理多个描述符时。

  2. 服务器在高并发处理网络连接的时候。

  3. 服务器既要处理监听套接口,又要处理已连接套接口,一般也要用到I/O复用。

  4. 如果一个服务器即要处理TCP,又要处理UDP,一般要使用I/O复用。

  5. 如果一个服务器要处理多个服务或多个协议,一般要使用I/O复用。

与多进程和多线程技术相比,I/O多路复用技术的最大优势是系统开销小,系统不必创建进程/线程,也不必维护这些进程/线程,从而大大减小了系统的开销。但select,poll,epoll本质上都是同步I/O,因为他们都需要在读写事件就绪后自己负责进行读写,也就是说这个读写过程是阻塞的,而异步I/O则无需自己负责进行读写,异步I/O的实现会负责把数据从内核拷贝到用户空间

select

用直白的话来介绍select:select机制会监听它所负责的所有socket,当其中一个socket或者多个socket可读或者可写的时候,它就会返回,而如果所有的socket都是不可读或者不可写的时候,这个进程就会被阻塞,直到超时或者socket可读写,当select函数返回后,可以通过遍历fdset,来找到就绪的描述符。

select整个处理过程如下

用户空间 内核空间 FD_ZERO() FD_SET() 调用select()函数 进程进入阻塞状 态,可能等到一 个或者多个so cket描述符就绪。 loop [ 遍历一遍fd ] 如果没有满足条件 的fd, 将进行 休眠, 在soc ket可读写时唤 醒, 或者在超时 后唤醒 返回 当select() 函数返回后, 可以 通过遍历fdset , 来找到就绪的描 述符, 再操作so cket 调用read()/recvfrom()等函数 将数据从内核空间 拷贝到用户空间 返回读取到的数据 用户空间 内核空间
  1. 用户进程调用select()函数,如果当前没有可读写的socket,则用户进程进入阻塞状态。
  2. 对于内核空间来说,它会从用户空间拷贝fd_set到内核空间,然后在内核中遍历一遍所有的socket描述符,如果没有满足条件的socket描述符,内核将进行休眠,当设备驱动发生自身资源可读写后,会唤醒其等待队列上睡眠的内核进程,即在socket可读写时唤醒,或者在超时后唤醒。
  3. 返回select()函数的调用结果给用户进程,返回就绪socket描述符的数目,超时返回0,出错返回-1。
  4. 注意,在select()函数返回后还是需要轮询去找到就绪的socket描述符的,此时用户进程才可以去操作socket

select目前几乎在所有的平台上支持,其良好跨平台支持也是它的一个优点。

当然select也有很多缺点:

  1. 单个进程能够监视的文件描述符的数量存在最大限制,在Linux上一般为1024,可以通过修改宏定义甚至重新编译内核的方式提升这一限制,但是这样也会造成效率的降低。
  2. 需要维护一个用来存放大量fd的数据结构,这样会使得用户空间和内核空间在传递该结构时复制开销大。
  3. 每次在有socket描述符活跃的时候,都需要遍历一遍所有的fd找到该描述符,这会带来大量的时间消耗(时间复杂度是O(n),并且伴随着描述符越多,这开销呈线性增长)

对应内核来说,整个处理的流程如下:

超时
返回
监听类型的socket
活跃连接的socket
设置socket的fd
可以返回
数据接收成功
数据接收失败
清除socket标志位
返回
返回
select
FD_ISSET
close
accept
recv
FD_SET
return
close
FD_CLR

select函数原型:

int select(int maxfdp1,fd_set *readset,fd_set *writeset,fd_set *exceptset,const struct timeval *timeout)

参数说明:

  • maxfdp1指定感兴趣的socket描述符个数,它的值是套接字最大socket描述符加1,socket描述符0、1、2 … maxfdp1-1均将被设置为感兴趣(即会查看他们是否可读、可写)。

  • readset:指定这个socket描述符是可读的时候才返回。

  • writeset:指定这个socket描述符是可写的时候才返回。

  • exceptset:指定这个socket描述符是异常条件时候才返回。

  • timeout:指定了超时的时间,当超时了也会返回。

如果对某一个的条件不感兴趣,就可以把它设为空指针。

返回值:就绪socket描述符的数目,超时返回0,出错返回-1。

select的缺点

  1. 每次调用select,都需要把fd集合从用户态拷贝到内核态,这个开销在fd很多时会很大。

  2. 同时每次调用select都需要在内核遍历传递进来的所有fd,这个开销在fd很多时也很大。

  3. 每次在select()函数返回后,都要通过遍历文件描述符来获取已经就绪的socket

  4. select支持的文件描述符数量太小了,默认是1024

poll

poll的实现和select非常相似,只是描述fd集合的方式不同,poll使用pollfd结构而不是selectfd_set结构,poll不限制socket描述符的个数,因为它是使用链表维护这些socket描述符的,其他的都差不多和select()函数一样,poll()函数返回后,需要轮询pollfd来获取就绪的描述符,根据描述符的状态进行处理,但是poll没有最大文件描述符数量的限制。pollselect同样存在一个缺点就是,包含大量文件描述符的数组被整体复制于用户态和内核的地址空间之间,而不论这些文件描述符是否就绪,它的开销随着文件描述符数量的增加而线性增大。

函数原型:

int poll (struct pollfd *fds, unsigned int nfds, int timeout);

epoll

epoll的原理

其实相对于selectpoll来说,epoll更加灵活,但是核心的原理都是当socket描述符就绪(可读、可写、出现异常),就会通知应用进程,告诉他哪个socket描述符就绪,只是通知处理的方式不同而已。

epoll使用一个epfd(epoll文件描述符)管理多个socket描述符,epoll不限制socket描述符的个数,将用户空间的socket描述符的事件存放到内核的一个事件表中,这样在用户空间和内核空间的copy只需一次。当epoll记录的socket产生就绪的时候,epoll会通过callback的方式来激活这个fd,这样子在epoll_wait便可以收到通知,告知应用层哪个socket就绪了,这种通知的方式是可以直接得到那个socket就绪的,因此相比于selectpoll,它不需要遍历socket列表,时间复杂度是O(1),不会因为记录的socket增多而导致开销变大。

epoll的操作模式

epoll对socket描述符的操作有两种模式:LT(level trigger)和ET(edge trigger)。LT模式是默认模式,LT模式与ET模式的区别如下:

  • LT模式:即水平出发模式,当epoll_wait检测到socket描述符处于就绪时就通知应用程序,应用程序可以不立即处理它。下次调用epoll_wait时,还会再次产生通知。

  • ET模式:即边缘触发模式,当epoll_wait检测到socket描述符处于就绪时就通知应用程序,应用程序必须立即处理它。如果不处理,下次调用epoll_wait时,不会再次产生通知。

ET模式在很大程度上减少了epoll事件被重复触发的次数,因此效率要比LT模式高。epoll工作在ET模式的时候,必须使用非阻塞套接口,以避免由于一个文件句柄的阻塞读/阻塞写操作把处理多个文件描述符的任务饿死。

epoll的函数

epoll只有epoll_create()、epoll_ctl()、epoll_wait() 3个系统调用函数。

epoll_create()

int epoll_create(int size);

创建一个epoll的epfd(epoll文件描述符,或者称之为句柄),当创建好epoll句柄后,它就是会占用一个fd值,必须调用close()关闭,否则可能导致fd被耗尽,这也是为什么我们前面所讲的是:epoll使用一个epfd管理多个socket描述符

size参数用来告诉内核这个监听的数目一共有多大,它其实是在内核申请一空间,用来存放用户想监听的socket fd上是否可读可行或者其他异常,只要有足够的内存空间,size可以随意设置大小,1G的内存上能监听约10万个端口。

epoll_ctl()

该函数用于控制某个epoll文件描述符上的事件,可以注册事件,修改事件,以及删除事件。

int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);

参数:

  • epdf:由epoll_create()函数返回的epoll文件描述符(句柄)。

  • op:op是操作的选项,目前有以下三个选项:

    • EPOLL_CTL_ADD:注册要监听的目标socket描述符fd到epoll句柄中。

    • EPOLL_CTL_MOD:修改epoll句柄已经注册的fd的监听事件。

    • EPOLL_CTL_DEL:从epoll句柄删除已经注册的socket描述符。

  • fd:指定监听的socket描述符。

  • event:event结构如下:

    typedef union epoll_data {
        void        *ptr;
        int          fd;
        uint32_t     u32;
        uint64_t     u64;
    } epoll_data_t;
    
    struct epoll_event {
        uint32_t     events;      /* Epoll events */
        epoll_data_t data;        /* User data variable */
    };
    
    • events可以是以下几个宏的集合:

      • EPOLLIN:表示对应的文件描述符可以读(包括对端SOCKET正常关闭)。

      • EPOLLOUT:表示对应的文件描述符可以写。

      • EPOLLPRI:表示对应的文件描述符有紧急的数据可读(这里应该表示有带外数据到来)。

      • EPOLLERR:表示对应的文件描述符发生错误。

      • EPOLLHUP:表示对应的文件描述符被挂断。

      • EPOLLET: 将EPOLL设为边缘触发(Edge Triggered)模式,这是相对于水平触发(Level Triggered)来说的。

      • EPOLLONESHOT:只监听一次事件,当监听完这次事件之后,如果还需要继续监听这个socket的话,需要再次把这个socket加入到EPOLL队列里。

epoll_wait()

int epoll_wait(int epfd, struct epoll_event *events,
               int maxevents, int timeout);

epoll_wait()函数的作用就是等待监听的事件的发生,类似于调用select()函数。

参数:

  • events:用来从内核得到事件的集合。

  • maxevents告之内核这个events有多大,这个 maxevents的值不能大于创建epoll_create()时的指定的size。

  • timeout是超时时间。

  • 函数的返回值表示需要处理的事件数目,如返回0表示已超时。

epoll为什么更高效

  1. 当我们调用epoll_wait()函数返回的不是实际的描述符,而是一个代表就绪描述符数量的值,这个时候需要去epoll指定的一个数组中依次取得相应数量的socket描述符即可,而不需要遍历扫描所有的socket描述符,因此这里的时间复杂度是O(1)。

  2. 此外还使用了内存映射(mmap)技术,这样便彻底省掉了这些socket描述符在系统调用时拷贝的开销(因为从用户空间到内核空间需要拷贝操作)。mmap将用户空间的一块地址和内核空间的一块地址同时映射到相同的一块物理内存地址(不管是用户空间还是内核空间都是虚拟地址,最终要通过地址映射映射到物理地址),使得这块物理内存对内核和对用户均可见,减少用户态和内核态之间的数据交换,不需要依赖拷贝,这样子内核可以直接看到epoll监听的socket描述符,效率极高。

  3. 另一个本质的改进在于epoll采用基于事件的就绪通知方式。在select/poll中,进程只有在调用一定的方法后,内核才对所有监视的socket描述符进行扫描,而epoll事先通过epoll_ctl()来注册一个socket描述符,一旦检测到epoll管理的socket描述符就绪时,内核会采用类似callback的回调机制,迅速激活这个socket描述符,当进程调用epoll_wait()时便可以得到通知,也就是说epoll最大的优点就在于它只管就绪的socket描述符,而跟socket描述符的总数无关

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

select、poll、epoll的原理与区别 的相关文章

  • VSCode与CMake搭配使用之基本配置

    1 首先安装VSCode插件CMake和CMake Tools CMake插件主要功能是CMake语法高亮 自动补全CMake Tools的功能主要是结合VSCode IDE使用CMake这个工具 xff0c 比如生成CMake项目 构建C
  • 九、设置元素等待

    转载于 xff1a http www testclass net selenium python element wait WebDriver提供了两种类型的等待 xff1a 显式等待和隐式等待 显式等待 显式等待使WebdDriver等待
  • Unity Tweak Tool使用

    这年头 xff0c 都讲究个性 Unity刚出来的时候 xff0c 就觉着新奇 xff0c 其他也没啥 xff0c 就是有些小不顺手 最开始使用的Ubuntu Tweak到后来的Gnome Tweak Tool都有点偏 xff0c ubun
  • MYSQL–my.cnf配置中文详解

    basedir 61 path 使用给定目录作为根目录 安装目录 character sets dir 61 path 给出存放着字符集的目录 datadir 61 path 从给定目录读取数据库文件 pid file 61 filenam
  • vscode中C/C++的Clang-format的使用

    一 介绍 Clang format是一个功能强大的格式化工具 在vs code通过C C 43 43 扩展后即可使用Clang format工具进行代码的格式化 其自带的排版格式主要有 xff1a LLVM Google Chromium
  • ShardingJDBC核心概念与快速实战

    目录 ShardingSphere介绍 ShardingSphere特点 ShardingSphere简述 ShardingSphere产品区分 ShardingJDBC实战 核心概念 实战 ShardingJDBC的分片算法 Shardi
  • 野火嵌入式学习笔记:第47讲 按键检测输入

    野火 第一期 Linux系列教学视频之 零基础入门 篇 xff0c 手把手教学 xff0c 从0开始 xff0c 基于野火i MX6ULL Pro MINI开发板 第47讲 检测按键输入 哔哩哔哩 bilibili 检测用户按键3 key按
  • 学习野火嵌入式笔记 第48讲:进程的由来

    野火 第二期 Linux系列教学视频之 内核编程 篇 xff0c 手把手教学 xff0c 硬件基于野火i MX6ULL Pro MINI开发板 野火 第二期 Linux系列教学视频之 内核编程 篇 xff0c 手把手教学 xff0c 硬件基
  • 学习野火嵌入式笔记:第68讲 I.MX^ULL 启动方式

    野火 第三期 Linux系列教学视频之 裸机开发 篇 xff0c 手把手教学 xff0c 基于野火i MX6ULL Pro MINI开发板 哔哩哔哩 bilibili 先了解其芯片手册以及linux开发板的原理图 全篇就在讲启动方式的引脚设
  • C语言 字符串-字符串的匹配

    字符串匹配函数 const char strstr const char str1 const char str2 搜索字符串在另一个字符串中首次出现的位置 const char p 61 strstr 34 how are you 34
  • Lambda表达式

    什么是Lambda表达式 Lambda 表达式是 Java8 新增的重要特性 xff0c Lambda 使 Java 具有了函数式编程的思想 xff0c 它的实质也是由编译器根据表达式推断最终生成原始语法的字节码方式 函数式编程思想是 强调
  • MPU6050多次发送数据,但第一次读取的数据为0

    实际现象并不是第一次数据为0 xff0c 一直读取数据 xff0c 中间也会出现数据为0的现象 xff0c 原因是 xff1a 跟采样频率有关 xff0c 如果采样频率为50Hz xff0c 那么读取数据间隔时间必须大于20ms xff0c
  • gazebo多机仿真时出现的问题解决方法

    多机仿真过程中出现的飞机不动的情况是 xff1a 下面几个步骤要严格执行 xff1a cd PX4 span class token operator span Autopilot git submodule update span cla
  • Linux c多线程与c++多线程的基础写法

    最近工作需要 xff0c 对多线程做了一点了解 xff0c 现在将多线程的创建 xff0c 函数传参做个小结 一 linux c多线程 1 头文件 xff1a include lt pthread h gt 2 创建线程 xff1a pth
  • 姿态误差问题

    前段同学问了一个关于飞机姿态误差的问题 xff0c 将飞机姿态直接做差与px4里面先z轴对齐然后将过渡矩阵的姿态量赋值给滚转俯仰姿态误差对比 xff0c 发现直接做差后在飞机做大的机动时误差量会变大 xff0c 曲线的拟合非常不好 xff0
  • px4 avoidance笔记

    最近在用px4官方的avoidance代码跑硬件避障 xff0c 官方介绍了只要生成符合sensor msgs PointCloud2点云信息就能使用 xff0c 因此为了应用长基线双目 xff0c 没有使用realsense的相机 xff
  • PX4源代码下载编译

    sudo git clone https github com PX4 PX4 Autopilot git recursivegit submodule update init recursivegit submodule update r
  • 踩坑记录

    ERROR Session line number was not unique in database History logging moved to new session 66 在生成tfrecord时 总报如下错误 找了很长时间
  • git强制覆盖本地代码

    git强制覆盖本地 xff1a git fetch all 拉取所有更新 git reset hard origin master 本地代码同步线上最新版本 会覆盖本地所有与远程仓库上同名的文件 git pull git强制覆盖本地命令 x
  • 【毕业设计】基于STM32及OpenMV的云台追踪装置

    目录 修改记录1 摘 要2 整体功能分析3 硬件选型3 1 OpenMV4 Cam H73 2 STM32F103ZET63 3 DS3120舵机3 4 LED补光板3 5 供电及稳压3 6 硬件连接 4 软件功能实现4 1 OpenMV部

随机推荐

  • firewall-cmd 使用总结

    firewalld的简要说明 firewalld firewall cmd firewall offline cmd它们Python脚本 xff0c 通过定义的在 usr lib firewalld下面的xml配置信息 xff0c 在启动时
  • 机架与机柜

    随着计算机网络的发展 xff0c 数据中心的服务器以及网络通信设备等IT设施 xff0c 正逐步向着网络化 机架化的方向发展 机架是用于综合布线 xff0c 安装配线架和理线架 xff0c 实现对电缆和光缆布线系统的管理 在网络机柜中不具备
  • cmake和makefile区别和cmake指定编译器(cmake -G)

    一 cmake和makefile区别 要说明区别 xff0c 我们先要区分下面三类工具 xff1a 1 项目构建生成工具 首先cmake是项目构建生成工具 xff0c cmake的代码可以与平台系统和编译器无关 类似cmake的工具还有au
  • Gazebo使用过程中的问题

    1 运行命令gazebo没有反应 在虚拟机安装好gazebo后 xff0c 使用ALT 43 F2打开命令行运行命令gazebo没有反应 首先尝试内存不够的情况 xff0c 给虚拟机加到了4g内存 没有用 xff0c 运行gazebo还是没
  • 一张图理解板卡硬件调试流程

    最近在调试从焊板厂打样回来的板卡 xff0c 简单总结了下板卡的硬件测试流程 xff0c 如下图 xff1a 写在后面的话 xff1a 我之所以选择做技术这一行 xff0c 是觉得做技术的人简单 直接 xff0c 当你面对一个技术问题 xf
  • 关于Linux进程你所需要知道的一切都在这里!!

    文章目录 进程简单了解进程查看进程进程ID父进程ID父进程与子进程 程序与进程程序进程程序变成进程总结 进程状态进程状态转换启动新进程system fork exce系列函数 终止进程等待进程wait waitpid 进程 说明 xff1a
  • MQTT协议简介及协议原理

    文章目录 MQTT协议MQTT协议简介MQTT通信模型MQTT客户端的功能 xff1a MQTT客户服务器功能 xff1a 消息主题与服务质量MQTT控制报文固定报头可变报头CONNECT报文CONNACK报文 有效载荷 MQTT协议 MQ
  • 你不得不看的图文并茂的MQTT协议通信过程!!!

    文章目录 MQTT连接服务器MQTT订阅主题MQTT发布消息服务质量等级 QoSQoS0的PUBLISH控制报文QoS1的PUBLISH控制报文QoS2的PUBLISH控制报文 取消订阅断开连接 MQTT连接服务器 客户端到服务器的网络连接
  • 一个高性能、高稳定性的跨平台MQTT客户端——mqttclient简介与使用

    文章目录 mqttclient简介与使用优势 xff1a 在线代码生成工具占用资源大小整体框架支持的平台版本问题版权和许可linux平台下测试使用安装cmake xff1a 测试程序编译 amp 运行编译成动态库libmqttclient
  • 一个高性能、高稳定性的跨平台MQTT客户端——mqttclient代码生产工具介绍

    文章目录 mqttclient代码生产工具介绍连接参数配置订阅主题相关的代码配置发布消息相关的代码配置生成代码 mqttclient代码生产工具介绍 mqttclient代码生产工具主要是用于配置MQTT的参数 xff0c 并且生成相应的代
  • 一个高性能、高稳定性的跨平台MQTT客户端——mqttclient配置及裁剪工具

    文章目录 mqttclient配置及裁剪工具salof相关的配置使用mqttclient裁剪配置工具 mqttclient配置及裁剪工具 MQTT TOPIC LEN MAX 配置客户端支持最大的主题名长度 xff0c 主题是支持通配符的
  • 一个高性能、高稳定性的跨平台MQTT客户端——mqttclient设计与实现方式

    文章目录 mqttclient设计与实现方式设计思想API接口MQTT客户端的核心结构mqttclient实现申请一个mqtt客户端释放已申请的mqtt客户端设置MQTT客户端的信息连接服务器订阅报文取消订阅发布报文内部线程核心的处理函数发
  • mqtt连接百度天工物接入平台

    文章目录 mqtt连接到百度天工物接入百度天工物接入简介使用百度天工物接入创建项目创建策略创建身份创建用户测试连接 MQTT软件测试连接手动安装相关的依赖包拉取mqttclient仓库简单介绍mqttclient仓库文件夹编译运行测试代码使
  • mqttclient连接到OneNET云平台

    文章目录 mqttclient连接到OneNET云平台使用OneNET测试连接手动安装相关的依赖包拉取mqttclient仓库简单介绍mqttclient仓库文件夹编译运行代码使用到的API mqttclient连接到OneNET云平台 有
  • 2022年最新《谷粒学院开发教程》:1 - 构建工程篇

    资料资料资料地址代码地址 后台管理系统目录前台展示系统目录1 构建工程篇7 渲染前台篇2 前后交互篇8 前台登录篇3 文件上传篇9 前台课程篇4 课程管理篇10 前台支付篇5 章节管理篇11 统计分析篇6 微服务治理12 项目完结篇 目录
  • MQTT移植到stm32开发板——使用RT-Thread操作系统

    文章目录 mqttclientENV介绍env工具下载安装通过env移植MQTT客户端打开 env 控制台打开env并更新软件包列表移植MQTT客户端 编写自己的代码 xff1a 连接参数配置订阅主题相关的代码配置发布消息相关的代码配置生成
  • MQTT移植到stm32开发板——使用TencentOS tiny操作系统

    mqttclient 一个高性能 高稳定性的跨平台MQTT客户端 一个高性能 高稳定性的跨平台MQTT客户端 xff0c 基于socket API之上开发 xff0c 可以在嵌入式设备 xff08 FreeRTOS LiteOS RT Th
  • MQTT移植到stm32开发板——使用FreeRTOS操作系统

    mqttclient 一个高性能 高稳定性的跨平台MQTT客户端 一个高性能 高稳定性的跨平台MQTT客户端 xff0c 基于socket API之上开发 xff0c 可以在嵌入式设备 xff08 FreeRTOS LiteOS RT Th
  • 深入了解C++多态的原理及实现方式

    文章目录 前言关于多态函数承载方式虚函数方式 前言 需要深入了解C C 43 43 语言的基础之上再看此文章 关于多态 具有多种形态 xff0c 调用同一个方法会随上下文不同而产生不同的结果 xff0c 多态有静态多态与动态多态两种 函数承
  • select、poll、epoll的原理与区别

    文章目录 前言同步I O异步I O阻塞I O非阻塞I O多路复用I Oselectselect整个处理过程如下select函数原型 xff1a select的缺点 pollepollepoll的原理epoll的操作模式epoll的函数epo