2.1.2 select poll epoll reactor

1. select 的使用方法

fd_set rdset;
FD_ZERO(&rdset);  // 清空 rdset
rdset = fdset;    // 将 fdset 拷贝到 rdset,准备传给 select
select(maxFd + 1, &rdset, NULL, NULL, NULL);
  • 参数说明
    • maxFd: 被监控的文件描述符中最大的一个。
    • maxFd + 1: 因为文件描述符从 0 开始,需要在最大值基础上加 1。
    • &rdset: 监控读事件的文件描述符集合。
    • NULL: 表示不监控写事件和异常事件。
    • NULL: 表示不设置超时时间,阻塞等待。

2. poll 的使用方法

数据结构
struct pollfd {int   fd;         /* 文件描述符 */short events;     /* 请求的事件:常用 POLLIN | POLLOUT */short revents;    /* 返回的事件 */
};
函数原型
int poll(struct pollfd *fds, nfds_t nfds, int timeout);
  • 参数说明
    • fds: 指向一个 pollfd 结构体数组或链表,存放需要监控的文件描述符及其事件。
    • nfds: fds 中的文件描述符数量。
    • timeout: 超时时间(毫秒)。
注意事项
  • events 描述需要监控的事件。
  • revents 返回实际发生的事件。
  • 如果 fds 中的文件描述符需要动态增删,建议使用链表以便管理;若为数组,删除操作会涉及数组元素移动。

3. epoll 的使用方法

数据结构
typedef union epoll_data {void *ptr;int fd;uint32_t u32;uint64_t u64;
} epoll_data_t;struct epoll_event {uint32_t events;  /* 监控的事件 */epoll_data_t data; /* 用户自定义数据 */
};
函数原型
int epoll_create(int size); // size 为历史遗留参数,只需 >0
int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);
int epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout);
示例代码
#define MAX_EVENTS 10
struct epoll_event ev, events[MAX_EVENTS];
int listen_sock, conn_sock, nfds, epollfd;/* 设置监听 socket (listen_sock),省略 socket(), bind(), listen() 等代码 */
epollfd = epoll_create(1);
if (epollfd == -1) {perror("epoll_create1");exit(EXIT_FAILURE);
}ev.events = EPOLLIN;
ev.data.fd = listen_sock;
if (epoll_ctl(epollfd, EPOLL_CTL_ADD, listen_sock, &ev) == -1) {perror("epoll_ctl: listen_sock");exit(EXIT_FAILURE);
}for (;;) {nfds = epoll_wait(epollfd, events, MAX_EVENTS, -1);if (nfds == -1) {perror("epoll_wait");exit(EXIT_FAILURE);}for (int n = 0; n < nfds; ++n) {if (events[n].data.fd == listen_sock) {conn_sock = accept(listen_sock, (struct sockaddr *)&addr, &addrlen);if (conn_sock == -1) {perror("accept");exit(EXIT_FAILURE);}setnonblocking(conn_sock);ev.events = EPOLLIN | EPOLLET;ev.data.fd = conn_sock;if (epoll_ctl(epollfd, EPOLL_CTL_ADD, conn_sock, &ev) == -1) {perror("epoll_ctl: conn_sock");exit(EXIT_FAILURE);}} else {do_use_fd(events[n].data.fd);}}
}
注意
  • 边缘触发 (ET)
    • 提高性能,避免频繁切换状态。
    • 需要非阻塞的文件描述符,并且在返回 EAGAIN 后继续读取/写入。
  • 监听多个事件
    • epoll_ctl 中可指定 EPOLLIN | EPOLLOUT,避免频繁切换。

4. epoll_ctldata 的作用

数据结构
typedef union epoll_data {void *ptr;int fd;uint32_t u32;uint64_t u64;
} epoll_data_t;
用途
  1. 数据关联
    • 将文件描述符与用户数据关联,在 epoll_wait 中可以直接访问。
  2. 灵活性
    • 支持存储指针(ptr)、文件描述符(fd)或整数数据(u32/u64)。
  3. 事件处理上下文传递
    • 存储指针时可在事件处理中快速获取上下文信息。
示例

假设有一个自定义结构体 my_data

struct my_data {int id;// 其他数据
};// 创建 epoll_event
struct epoll_event ev;
struct my_data *data = malloc(sizeof(struct my_data));
data->id = 123;
ev.events = EPOLLIN;
ev.data.ptr = data;// 添加文件描述符
epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fd, &ev);// 事件触发后处理
int n = epoll_wait(epoll_fd, events, maxevents, timeout);
for (int i = 0; i < n; i++) {struct my_data *data = (struct my_data *)events[i].data.ptr;printf("触发事件的 ID: %d\n", data->id);
}

总结
方法特点使用场景
select简单、支持多平台,需多次拷贝 fd_set适合少量文件描述符监控
poll动态数组,支持更多事件类型适合动态增加/删除描述符
epoll高效、支持边缘触发,用户可存储上下文信息,适合大量并发场景高性能服务器、并发场景

5.epoll 的优势

1. 性能优势(O(1)复杂度)
  • select 和 poll:
    • 性能随监控的文件描述符数量增加而线性下降(O(n)),因为每次调用时,内核需要遍历整个文件描述符集,检查每一个文件描述符的状态。
    • 当有大量文件描述符(如几千或几万个)时,这种线性扫描会导致性能大幅下降,尤其是当大多数文件描述符可能处于空闲状态时。
  • epoll:
    • epoll 的设计避免了线性扫描,采用事件驱动机制。当文件描述符状态变化时,内核会通知应用程序。
    • 性能与文件描述符数量无关,复杂度为 O(1)。
    • 使用基于回调机制的红黑树管理事件,只有发生事件的文件描述符才会被处理,大大减少了不必要的遍历。
2. 支持大量文件描述符
  • select:
    • 文件描述符集大小有限,在许多系统(如 Linux)上默认最多处理 1024 个文件描述符。虽然可以通过修改系统配置或编译选项增加限制,但仍是额外负担。
  • poll:
    • 无硬性限制,但性能瓶颈仍存在。监控大量文件描述符时,需要对整个文件描述符集进行线性遍历。
  • epoll:
    • 没有硬性限制(受限于系统允许的最大文件描述符数量),且处理大量文件描述符时性能几乎不受影响。
3. 事件驱动机制
  • select 和 poll:
    • 采用轮询方式,每次调用时必须检查所有文件描述符的状态,即使大部分文件描述符没有事件发生,也需要遍历整个列表。
  • epoll:
    • 提供事件通知机制,只有发生事件时,相关文件描述符才会被加入到就绪列表中。只有当事件发生时,epoll 才会处理相应文件描述符,避免不必要的轮询。
4. 持久模式 vs. 边缘触发模式
  • select 和 poll:
    • 都是水平触发(Level-triggered),每次调用都需要检查所有文件描述符的状态,即使事件已被处理完,下次调用时仍然返回。
  • epoll:
    • 支持两种模式:
      1. 水平触发(Level-triggered,默认): 与 select 和 poll 类似,当文件描述符有数据可读时,它会在每次 epoll_wait 时返回,直到数据被完全处理。
      2. 边缘触发(Edge-triggered): 文件描述符从空闲变为有事件时才会通知,不会重复通知。此模式效率高,但要求程序一次性处理所有数据,否则可能丢失事件。
5. 避免频繁的文件描述符集重建
  • select 和 poll:
    • 每次调用都需重新构建文件描述符集,带来额外开销。尤其在大量文件描述符的场景下,这种开销非常显著。
  • epoll:
    • 文件描述符集在调用 epoll_ctl 时构建并持久化,无需每次调用 epoll_wait 时重新构建。只有在增加、删除或修改感兴趣事件时才需调用 epoll_ctl 更改。
6. 内存复制开销
  • select 和 poll:
    • 每次调用时,文件描述符集需从用户空间复制到内核空间,结果再复制回用户空间。这种频繁的内存复制会带来较大开销。
  • epoll:
    • 仅在 epoll_ctl 调用时传递文件描述符信息给内核,epoll_wait 只返回就绪文件描述符,避免频繁的大量内存复制。
总结
  • 性能: epoll 在大量文件描述符场景下表现优越,特别是大多数文件描述符处于空闲状态时。
  • 可扩展性: epoll 可处理大量文件描述符,无硬性限制。
  • 事件驱动: epoll 通过事件通知机制避免了轮询的开销。
  • 模式选择: epoll 支持边缘触发模式,进一步提升效率。

6.epoll 的水平触发和边缘触发配置

1. 水平触发(Level-triggered)
  • epoll 的默认模式。
  • 只要文件描述符处于就绪状态,epoll_wait 每次调用都会返回该文件描述符,直到事件被处理(如数据被读取完毕)。
2. 边缘触发(Edge-triggered)
  • 当文件描述符状态从未就绪变为就绪时,epoll_wait 才会通知。
  • 更加高效,但要求程序能够一次性处理所有就绪数据或事件,避免数据残留在缓冲区中。
配置方法

使用 epoll_ctl 添加或修改文件描述符时,通过设置事件标志启用对应模式。

水平触发示例(默认模式):

struct epoll_event ev;
ev.events = EPOLLIN;  // 监听可读事件(默认水平触发)
ev.data.fd = fd;      // 文件描述符
// 将 fd 添加到 epoll 实例中
epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fd, &ev);

边缘触发示例(启用 EPOLLET):

struct epoll_event ev;
ev.events = EPOLLIN | EPOLLET;  // 启用边缘触发模式,并监听可读事件
ev.data.fd = fd;                // 文件描述符
// 将 fd 添加到 epoll 实例中
epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fd, &ev);
注意事项
  1. 边缘触发必须一次性读取所有数据:
    • 若数据未全部读取,后续 epoll_wait 不会再通知该文件描述符有未处理数据。
  2. 使用非阻塞 I/O:
    • 避免因数据不足或缓冲区不足而阻塞程序。
    • 设置文件描述符为非阻塞模式:
      int flags = fcntl(fd, F_GETFL, 0);
      fcntl(fd, F_SETFL, flags | O_NONBLOCK);  // 设置为非阻塞模式
      
总结
  • 水平触发: 默认模式,无需额外配置。
  • 边缘触发: 在 epoll_event 的 events 字段中添加 EPOLLET 标志即可启用。

7. reactor 模式:

1 附件说明:

.c为 epoll改造实现的reactor代码例程  

图片是验证效果

2 reactor设计流程
  1. 基于把网络IO的操作 和 上层业务代码隔离的思想,通过epoll_wait监控所有的listen_fd和client_fd,利用监控的事件类型events(IN、OUT)回调每个fd对应的回调函数。
  2. 基于上面所说,所有的fd都要绑定在一套结构体类型上,这个结构体中有IN事件对应的recv回调函数,有OUT事件对应的send回调函数。还需要定义接收数据和发送数据的缓存区,以及两个缓存区大小的变量。还有fd。
  3. 每次epoll_ctl设置EPOLLIN/EPOLLOUT只能设置一种,因为需要通过每一次的设置触发一次接收或是发送的回调

8.为什么 select 调用之前要把 rdset 清空重置?

在每次调用 select 之前,必须清空并重置 rdset,这是因为 select 会修改传入的文件描述符集(fd_set),以反映哪些文件描述符变得可读、可写或发生了异常。当 select 返回时,传入的 rdset 会只保留那些已经就绪的文件描述符,其它未就绪的文件描述符会被清除。

因此,在每次调用 select 前,需要重置 rdset,使其包含所有需要监控的文件描述符。否则,如果直接使用上一次 select 调用后被修改的 rdset,就会丢失未被清除的文件描述符信息。

简化流程:

  1. fdset 是原始的文件描述符集,包含所有需要监控的描述符(如 sockfd 和各个客户端 clientfd)。
  2. 每次调用 select 前,将 fdset 复制到 rdset(用于可读性检查)。
  3. select 会修改 rdset,清除未准备好的文件描述符,只保留那些就绪的文件描述符。
  4. 为了下一次 select 调用,必须再次用 fdset 重新初始化 rdset,否则上次修改的 rdset 会影响新的结果。

示例代码:

fd_set rdset;
FD_ZERO(&rdset);  // 清空 rdset
rdset = fdset;    // 将 fdset 拷贝到 rdset,准备传给 select
select(maxFd + 1, &rdset, NULL, NULL, NULL);
fd_set 类型

fd_set 是一个结构体类型,用于表示一组文件描述符集,通常与 select 函数配合使用,用于监控文件描述符是否就绪(可读、可写或有异常)。

在 POSIX 标准中,fd_set 通常被实现为一个位图(bit mask),每个文件描述符(整型值)对应一个位,表示该文件描述符是否在集合中。

常用宏:

  • FD_ZERO(fd_set *set):初始化一个空的文件描述符集。
  • FD_SET(int fd, fd_set *set):将文件描述符 fd 加入到文件描述符集中。
  • FD_CLR(int fd, fd_set *set):从文件描述符集中移除文件描述符 fd
  • FD_ISSET(int fd, fd_set *set):检查文件描述符 fd 是否在文件描述符集中。

内部实现通常如下:

typedef struct {unsigned long fds_bits[__FD_SETSIZE / (8 * sizeof(unsigned long))];
} fd_set;
  • fds_bits 是一个位数组,每一位代表一个文件描述符是否处于就绪状态。
  • __FD_SETSIZE 通常是 1024,表示可以同时监控的文件描述符数量。

9.select/poll/epoll 的超时参数是相对时间还是绝对时间?

select超时机制

select 函数的最后一个参数 timeout 是一个 struct timeval* 类型,表示超时时间。这个时间是相对时间,而不是绝对时间,因此系统时间的跳变不会影响 select 的超时行为。

具体说明:

  1. 相对时间struct timeval 定义的是相对时间,表示从调用 select 开始计算的等待时间,是以经过的时间为基准,而不是某个特定的系统时刻。

    struct timeval 结构如下:

    struct timeval {long tv_sec;  // 秒long tv_usec; // 微秒
    };
    

    select 使用的是相对时间,并不会受到系统时钟跳变的影响。

  2. 系统时间跳变的影响: 因为 select 使用的是相对时间,基于单调计时器(monotonic clock),所以即使系统时间发生跳变(例如系统时间调整或 NTP 时间同步),也不会影响 select 的超时计算。例如,如果设置超时为 5 秒,系统时钟被调整了 1 小时,select 依然会在约 5 秒后返回。

  3. timeout 参数解释

    • 如果 timeout 设置为 NULLselect 将无限等待,直到有文件描述符变为就绪。
    • 如果 timeout 设置为一个 struct timeval 结构指针,则 select 最多等待给定的相对时间。
    • 如果 timeouttv_sectv_usec 都为 0,select 将立即返回,完成一个非阻塞的检查。

示例:

struct timeval timeout;
timeout.tv_sec = 5;
timeout.tv_usec = 0;select(maxfd + 1, &readfds, NULL, NULL, &timeout);

即使系统时间发生跳变,select 依然会在大约 5 秒后超时返回。

pollepoll 的超时机制

pollepoll 的超时机制与 select 类似,它们也使用相对时间,因此系统时间的跳变不会影响它们的超时行为。

  1. poll 的超时机制poll 函数的超时参数是一个以毫秒为单位的整数,表示相对时间,系统时间的跳变不会影响超时行为。

    poll 的原型:

    int poll(struct pollfd *fds, nfds_t nfds, int timeout);
    
    • timeout:表示等待的相对时间(毫秒)。如果 timeout 是 0,表示立即返回;如果是负数,表示无限期等待。

    示例:

    poll(fds, nfds, 5000);  // 等待 5000 毫秒(5 秒)
    
  2. epoll 的超时机制epoll_wait 的超时参数同样是相对时间,单位是毫秒。系统时间跳变不会影响其超时行为。

    epoll_wait 的原型:

    int epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout);
    
    • timeout:表示相对时间(毫秒)。如果为 -1,表示无限等待;如果为 0,表示立即返回;为正数则等待指定的时间(毫秒)。

    示例:

    epoll_wait(epfd, events, maxevents, 5000);  // 等待 5000 毫秒(5 秒)
    
小结:
  • selectpollepoll 使用相对时间作为超时计算基准。
  • 系统时间的跳变不会影响它们的超时行为,因为它们依赖于单调计时器。

10.平时使用中该怎么选择使用select / poll/ epoll哪个接口

在选择 select、poll 或 epoll 作为 I/O 多路复用的接口时,取决于应用场景的需求和具体系统资源的使用情况。以下是关于如何选择这三者的一些建议:

1. select 适用场景:

select 是最早被引入的 I/O 多路复用机制,使用最广泛,适合以下情况:

  • 少量文件描述符:select 的文件描述符集有硬性限制(通常是 1024),因此适合监控文件描述符数量较少的应用(如几十个)。
  • 跨平台兼容性:如果应用需要在不支持 epoll 的平台上运行(如某些 BSD 系统、macOS 等),select 是一个通用选择。
  • 简单场景:对于一些简单的、少量的 I/O 监控任务,select 足够使用,且其 API 更为广泛被了解。

优势:

  • 兼容性好:几乎所有的 Unix 系统和 Windows 系统都支持。

劣势:

  • 性能较差:当需要监控大量文件描述符时,select 每次都需要线性扫描整个文件描述符集,性能会迅速下降。
  • 文件描述符限制:不能监控超过 1024 个文件描述符,除非手动修改系统配置。
  • 每次调用时需要重建文件描述符集:select 会修改原始的文件描述符集,因此在每次调用前都需要重新设置该集。
2. poll 适用场景:

poll 是对 select 的增强,它消除了 select 的文件描述符数量限制,但其内部实现仍然是线性扫描,因此在大规模场景中仍然性能不足。

  • 适中数量的文件描述符:如果你需要监控的文件描述符数量中等,poll 可以替代 select,因为它没有文件描述符数量的硬限制。
  • 跨平台并支持大规模描述符:poll 在大多数平台上支持且没有 1024 文件描述符的限制,相对适合一些描述符数量介于几十到几百的场景。
  • 复杂 I/O 场景:相比 select,poll 支持更多灵活的事件标志(如 POLLERR、POLLHUP 等),适合需要监听多种事件的场景。

优势:

  • 无硬性文件描述符数量限制
  • 支持更多事件:相较于 select,poll 能处理更多种类的事件,能够更灵活地监控 I/O 状态。

劣势:

  • 性能问题:当文件描述符数量增加时,poll 和 select 一样,每次调用都需要遍历整个文件描述符列表,性能会随着文件描述符数量线性下降。
  • 每次调用仍需要重建文件描述符集:和 select 类似,每次调用 poll 都需要重新设置感兴趣的文件描述符集。
3. epoll 适用场景:

epoll 是 Linux 提供的高性能 I/O 多路复用机制,特别适用于需要处理大量并发连接的大规模应用场景。

  • 大量文件描述符:如果你的应用需要监控几千甚至几万个文件描述符,epoll 是最佳选择。它通过事件驱动的机制,避免了每次都要遍历整个文件描述符集。
  • 长连接场景:如服务器端的网络应用,尤其是需要处理大量空闲连接(如长连接或 WebSocket),epoll 能在这种场景下表现出色,因为它只会在有事件发生时通知,而不是不断轮询空闲的连接。
  • 高性能和低延迟需求:对于一些需要低延迟、高吞吐量的系统,epoll 的边缘触发模式能进一步提高效率,避免无意义的系统调用。

优势:

  • 高效处理大规模并发连接:即使有大量文件描述符,epoll 也能高效处理,避免了 select 和 poll 的线性性能瓶颈。
  • 事件驱动模型:epoll 只在有事件发生时返回,性能更加优越。
  • 无描述符数量限制:epoll 没有文件描述符数量的硬性限制,取决于系统的最大打开文件数(ulimit -n)。

劣势:

  • 仅在 Linux 平台支持:epoll 是 Linux 专有的 API,如果需要跨平台支持,它就不适合。
  • 复杂度稍高:与 select 和 poll 相比,epoll 的 API 需要管理文件描述符的注册、修改、删除,有些应用场景下实现起来可能稍显复杂。
4.选择总结:
  • 选择 select
    • 文件描述符数量少于 1024 个,并且需要跨平台支持。
    • 场景简单,性能要求不高。
    • 几十个描述符的场景
  • 选择 poll
    • 文件描述符数量中等,跨平台需求。
    • 需要处理多种 I/O 事件且不希望受限于 select 的 1024 限制。
    • 几十几百文件描述符的场景
  • 选择 epoll
    • 处理大量文件描述符(成千上万个,如果硬件支持可达百万),并且系统为 Linux。
    • 需要处理高并发的网络服务,且希望性能高效,延迟低。
    • 希望使用事件驱动模型而不是轮询。

应用场景举例:

  • 高性能 Web 服务器或代理服务器(如 Nginx):使用 epoll 处理大规模并发连接。
  • 简单的命令行工具或小型服务器:可以使用 select 或 poll。
  • 跨平台的网络应用:使用 poll 或 select。

未来扩展:

在现代 Linux 系统中,epoll 是处理大规模并发和高性能网络应用的首选。如果你的应用主要在 Linux 环境运行,建议优先考虑 epoll。如果需要跨平台兼容性,poll 会比 select 更适合。


https://github.com/0voice

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/65108.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

vscode安装fortran插件配置

本章教程,主要介绍如何在vscode上安装fortran插件,以便于使用vscode运行fortran编写的程序。 一、安装插件 首先在插件商店安装这个扩展插件 然后再把Code Runner扩展插件装上 二、下载mingw64 通过网盘分享的文件:mingw64 链接: https://pan.baidu.com/s/1fwS-CwC7dgI

企业该如何进行合格文件外发管理

随着信息技术的迅猛发展&#xff0c;企业间的文件交换变得越来越频繁。但是&#xff0c;如何确保文件传输的安全性与效率&#xff0c;成为企业管理者面临的一个重大挑战。镭速&#xff08;Raysync&#xff09;文件外发管理方案以其独特的优势&#xff0c;成为众多企业的首选。本…

(Python+selenium)UI自动化测试详解

&#x1f345; 点击文末小卡片&#xff0c;免费获取软件测试全套资料&#xff0c;资料在手&#xff0c;涨薪更快 我们在进行UI自动化测试时&#xff0c;一般采用javaselenium或者pythonselenium的方式。由于python比较简单&#xff0c;上手快&#xff0c;因此建议大家采用pyt…

使用openvino加速部署paddleocr文本检测模型(C++版)

使用openvino加速部署paddleocr文本检测模型(C++版) 引言1,前处理2,后处理3,C++部署代码引言 文本检测在openvino部署端的前后处理与在paddleocr中的不太一样。 1,前处理 在将文本检测的模型转换成onnx格式(输入输出大小都已固定),并部署到openvino后,其预处理后的输…

2021-04-08 VSC++: 降序折半查找。

void 降序折半查找(int* a, int aa, int aaa) {//缘由https://bbs.csdn.net/topics/399166569int aaaa aaa / 2; bool k 0;if (a[0] aa){cout << 0, cout << ends << "查找&#xff1a;" << aa << endl;k 1;return;}else if (a[aa…

MySQL三层B+树能存多少数据

结论 bigint类型的索引&#xff08;8字节&#xff09;&#xff0c;一条数据假设是1KB的话&#xff0c; 三层B树 能存2000万条数据 该题主要考察数据如何在B树中存储的 计算思路 1.计算叶节点的大小 2.计算子节点的个数&#xff0c;由此算出第三层叶子节点的个数&#xff08;n*n…

win系统B站播放8k视频启用HEVC编码

下载HEVC插件 点击 HEVC Video Extension 2.2.20.0 latest downloads&#xff0c;根据教程下载安装 安装 Random User-Agent 点击 Random User-Agent 安装 配置 Random User-Agent ![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/dda0ea75096c42c0a79ef6f6f5521…

中伟视界:AI识别摄像头+AI预警平台在矿山皮带空载监测中的应用

在矿山开采和矿物处理过程中&#xff0c;皮带运输机扮演着举足轻重的角色。它们负责将矿石、煤炭等物料从一处运送到另一处&#xff0c;是矿山生产流程中不可或缺的一环。然而&#xff0c;皮带运输机在运行过程中也面临着一些挑战&#xff0c;其中之一便是皮带空载问题。皮带空…

实训项目-人力资源管理系统-1Company子模块

目录 前言&#xff1a; 用例图设计&#xff1a; 系统设计 开发方式&#xff1a; 技术架构 系统结构&#xff1a; API文档&#xff1a; 工程搭建&#xff1a; 搭建父项目 pom&#xff1a; 创建公共子模块&#xff1a; 返回实体&#xff1a; 分布式id生成器&#xff1a; …

2.5.3 文件使用、共享、保护、安全与可靠性

文章目录 文件使用文件共享文件保护系统安全与可靠性 文件使用 操作系统向用户提供操作级、编程级文件服务。 操作级服务包括目录管理&#xff0c;文件操作&#xff08;复制、删除、修改&#xff09;&#xff0c;文件管理&#xff08;设置文件权限&#xff09;。 编程级服务包括…

路由器转发数据报的封装过程

✍作者&#xff1a;柒烨带你飞 &#x1f4aa;格言&#xff1a;生活的情况越艰难&#xff0c;我越感到自己更坚强&#xff1b;我这个人走得很慢&#xff0c;但我从不后退。 &#x1f4dc;系列专栏&#xff1a;网路安全入门系列 目录 路由器转发数据的封装过程 路由器转发数据的封…

vulnhub matrix-breakout靶机

1.搭建靶机 这样就是装好了 获取靶机IP nmap -O 192.168.47.129/24 2.信息收集 dirb http://192.168.47.128 dirb 首页 81端口一个登录页面 gobuster dir -u http://192.168.152.154 -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt -x php,txt,html gra…

微信小程序 不同角色进入不同页面、呈现不同底部导航栏

遇到这个需求之前一直使用的小程序默认底部导航栏&#xff0c;且小程序默认入口页面为pages/index/index&#xff0c;要使不同角色呈现不同底部导航栏&#xff0c;必须要在不同页面引用不同的自定义导航栏。本篇将结合分包&#xff08;subPackages&#xff09;展开以下三步叙述…

如何通过 Kafka 将数据导入 Elasticsearch

作者&#xff1a;来自 Elastic Andre Luiz 将 Apache Kafka 与 Elasticsearch 集成的分步指南&#xff0c;以便使用 Python、Docker Compose 和 Kafka Connect 实现高效的数据提取、索引和可视化。 在本文中&#xff0c;我们将展示如何将 Apache Kafka 与 Elasticsearch 集成以…

LLaMA-Factory GLM4-9B-CHAT LoRA 微调实战

&#x1f929;LLaMA-Factory GLM LoRA 微调 安装llama-factory包 git clone --depth 1 https://github.com/hiyouga/LLaMA-Factory.git进入下载好的llama-factory&#xff0c;安装依赖包 cd LLaMA-Factory pip install -e ".[torch,metrics]" #上面这步操作会完成…

view draw aosp15

基础/背景知识 如何理解Drawable&#xff1f; 在 Android 中&#xff0c;Drawable 是一个抽象的概念&#xff0c;表示可以绘制到屏幕上的内容。 它可以是位图图像、矢量图形、形状、颜色等。 Drawable 本身并不是一个 View&#xff0c;它不能直接添加到布局中&#xff0c;而是…

gridcontrol表格某一列设置成复选框,选择多行(repositoryItemCheckEdit1)

1. 往表格中添加repositoryItemCheckEdit1 2. 事件&#xff1a; repositoryItemCheckEdit1.QueryCheckStateByValue repositoryItemCheckEdit1_QueryCheckStateByValue; private void repositoryItemCheckEdit1_QueryCheckStateByValue(object sender, DevExpress.XtraEditor…

重温设计模式--适配器模式

文章目录 适配器模式&#xff08;Adapter Pattern&#xff09;概述适配器模式UML图适配器模式的结构目标接口&#xff08;Target&#xff09;&#xff1a;适配器&#xff08;Adapter&#xff09;&#xff1a;被适配者&#xff08;Adaptee&#xff09;&#xff1a; 作用&#xf…

C语言项目 天天酷跑(上篇)

前言 这里讲述这个天天酷跑是怎么实现的&#xff0c;我会在天天酷跑的下篇添加源代码&#xff0c;这里会讲述天天酷跑这个项目是如何实现的每一个思路&#xff0c;都是作者自己学习于别人的代码而创作的项目和思路&#xff0c;这个代码和网上有些许不一样&#xff0c;因为掺杂了…

公交车信息管理系统:构建智能城市交通的基石

程序设计 本系统主要使用Java语言编码设计功能&#xff0c;MySQL数据库管控数据信息&#xff0c;SSM框架创建系统架构&#xff0c;通过这些关键技术对系统进行详细设计&#xff0c;设计和实现系统相关的功能模块。最后对系统进行测试&#xff0c;这一环节的结果&#xff0c;基本…