做网站大量视频怎么存储,网站建设中目录是什么意思,怎么推广自己的店铺,app搭建流程欢迎来到Cefler的博客#x1f601; #x1f54c;博客主页#xff1a;折纸花满衣 #x1f3e0;个人专栏#xff1a;Linux 目录 #x1f449;#x1f3fb;五种IO模型#x1f449;#x1f3fb;消息通信的同步异步与进程线程的同步异步有什么不同#xff1f;#x1f449… 欢迎来到Cefler的博客 博客主页折纸花满衣 个人专栏Linux 目录 五种IO模型消息通信的同步异步与进程线程的同步异步有什么不同非阻塞IOfcntl函数 I/O多路转接之selectselect函数select使用示例: 检测标准输入输出 I/O多路转接之pollpoll函数poll示例: 使用poll监控标准输入 I/O多路转接之epoll简单介绍epoll_create()、epoll_ctl()和epoll_wait()epoll_event结构体epoll示例: 使用epoll监控标准输入 五种IO模型 网络高级IO的五大模型主要包括 阻塞IOBlocking IO 描述在内核将数据准备好之前系统调用会一直等待。所有的套接字默认都是阻塞方式。示例服务端在处理客户端的连接和数据时会阻塞在accept和read操作上等待建立连接和读取数据。特点两个阶段等待读就绪和读数据都是阻塞的。 非阻塞IONon-blocking IO 描述如果内核还未将数据准备好系统调用仍然会直接返回并返回EWOULDBLOCK错误码。示例虽然可以通过多线程实现伪非阻塞但真正的非阻塞IO需要操作系统提供非阻塞的支持。特点用户进程发起请求后如果数据未准备好则立即返回不会阻塞用户进程。 IO多路复用IO Multiplexing 描述通过一种机制如select、poll、epoll等同时监控多个文件描述符的就绪状态从而避免阻塞在单个文件描述符上。示例select是其中一种实现方式它使用事件集合方式来监控多个文件描述符。特点能够同时等待多个文件描述符的就绪状态提高IO效率。 信号驱动IOSignal-driven IO 描述内核将数据准备好的时候使用SIGIO信号通知应用程序进行IO操作。示例在处理僵尸进程时可以使用信号来通知父进程回收子进程的退出信息。特点通过信号机制来通知应用程序进行IO操作避免了轮询的开销。 异步IOAsynchronous IO 描述由内核在数据拷贝完成时通知应用程序。示例类似于钓鱼的比喻异步IO是“帮你钓鱼”即内核完成数据拷贝后通知应用程序。特点应用程序不需要等待数据拷贝完成内核在数据拷贝完成后会主动通知应用程序。
这五大模型各有特点适用于不同的场景和需求。在实际应用中需要根据具体情况选择合适的IO模型来提高程序的性能和效率。
参考文章浅谈5种IO模型
消息通信的同步异步与进程线程的同步异步有什么不同
消息通信的同步异步与进程线程的同步异步在概念和应用上存在一些差异以下是具体的分析和归纳 消息通信的同步与异步 定义 同步在消息通信中同步意味着发送方发送消息后会等待接收方的响应即一次调用一次返回。发送方在收到接收方的响应之前不会继续执行其他操作。异步异步通信中发送方发送消息后不会立即等待接收方的响应而是继续执行其他操作。接收方在接收到消息后会通过某种方式如回调函数、事件通知等通知发送方。 特点 同步 严格按照顺序执行发送方和接收方之间保持紧密的同步关系。适用于需要确保消息被正确处理并获取结果的情况。可能会降低系统效率因为发送方需要等待接收方的响应。 异步 发送方和接收方之间相对独立发送方发送消息后可以继续执行其他任务。适用于需要并行处理多个任务或不需要立即获取结果的情况。可以提高系统效率因为发送方不需要等待接收方的响应。 进程与线程的同步与异步 定义 同步在进程或线程中同步指的是多个任务按照特定的顺序依次执行即一个任务执行完毕后再开始执行下一个任务。异步异步则是指多个任务可以同时执行不需要等待前一个任务完成。 特点 同步 确保任务的顺序执行有助于管理资源和避免竞态条件。可能会降低系统效率因为需要等待前一个任务完成才能开始下一个任务。 异步 提高系统效率允许多个任务同时执行。需要额外的机制来管理任务之间的依赖关系和协调资源的访问。
总结
消息通信的同步异步与进程线程的同步异步在概念上有所相似但应用场景和关注点有所不同。消息通信主要关注消息发送和接收之间的同步或异步关系而进程线程的同步异步则关注任务之间的执行顺序和并发性。在实际应用中需要根据具体的需求和场景来选择合适的同步异步方式。
非阻塞IO
fcntl函数
fcntl函数是计算机中用于文件描述符控制的一种函数它允许对已打开的文件性质进行修改。以下是fcntl函数的用法介绍 一、函数声明
#include fcntl.h
#include unistd.hint fcntl(int fd, int cmd, ...);fcntl函数接受三个参数
fd文件描述符代表要操作的已打开文件。cmd操作命令指定要对文件描述符进行的操作类型。…可选参数根据cmd的值可能需要一个int arg或struct flock *lock作为第三个参数。 二、功能介绍
fcntl函数根据cmd参数的值执行不同的操作主要有以下几种 F_DUPFD 复制一个现有的文件描述符。查找大于或等于参数arg的最小且仍未使用的文件描述符并复制参数fd的文件描述符。成功时返回新复制的文件描述符。 F_GETFD/F_SETFD F_GETFD取得与文件描述符fd联合的close-on-exec标志。F_SETFD设置close-on-exec标志。如果文件描述符设置了此标志则在执行exec()相关函数时文件将被关闭。 F_GETFL/F_SETFL F_GETFL取得文件描述符状态标志。F_SETFL设置文件描述符状态标志。可以更改的标志包括O_APPEND追加写、O_NONBLOCK非阻塞IO和O_ASYNC异步IO通知。 F_GETLK/F_SETLK/F_SETLKW 用于获取、设置和等待文件锁。F_SETLKW与F_SETLK功能相同但无法建立锁定时会阻塞等待。 F_GETOWN/F_SETOWN 用于获取/设置异步IO的所有权即哪个进程或线程将接收SIGIO和SIGURG信号。 三、返回值
如果成功根据cmd的值fcntl可能返回不同的值。如果出错所有命令都返回-1并设置全局变量errno以指示错误。
四、使用实例
在网络编程中fcntl常被用于将文件描述符设置为非阻塞模式以便在数据未就绪时不会阻塞进程。以下是一个简单的示例展示了如何使用fcntl将标准输入设置为非阻塞模式
#include unistd.h
#include fcntl.h
#include errno.h
#include stdio.hint main(void) {int flags, n;//char buf[10];// 获取stdin的当前标志flags fcntl(STDIN_FILENO, F_GETFL);if (flags -1) {perror(fcntl error);return 1;}// 添加O_NONBLOCK标志flags | O_NONBLOCK;// 设置stdin为非阻塞模式if (fcntl(STDIN_FILENO, F_SETFL, flags) -1) {perror(fcntl error);return 1;}// 接下来的read调用将不会阻塞如果数据未就绪将返回-1并设置errno为EAGAIN或EWOULDBLOCK// ...while (1) {char buf[1024] {0};ssize_t read_size read(0, buf, sizeof(buf) - 1);if (read_size 0) {perror(read:);sleep(1);continue;}printf(input:%s\n, buf);}return 0;
}五、总结
fcntl是一个功能强大的函数它允许程序对文件描述符进行精细的控制。通过fcntl程序可以改变文件的性质、设置锁、更改异步IO行为等。在编写涉及文件操作或网络编程的程序时fcntl是一个值得了解和掌握的函数。
I/O多路转接之select
select函数
select函数是一个用于I/O多路复用的系统调用它允许程序监视多个文件描述符的状态变化例如可读、可写或发生异常。这对于实现高效的I/O操作尤其是非阻塞I/O和服务器程序中的并发处理非常有用。 一、函数声明
在POSIX兼容的系统中select函数的声明通常如下
#include sys/select.h
#include sys/time.hint select(int nfds, fd_set *readfds, fd_set *writefds,fd_set *exceptfds, struct timeval *timeout);二、参数说明
nfds指定被监听的文件描述符集合中最大文件描述符加1。通常设置为监听的文件描述符集合中的最大值加1。readfds指向一个文件描述符集合的指针该集合中的文件描述符用于监视读状态变化。writefds指向一个文件描述符集合的指针该集合中的文件描述符用于监视写状态变化。exceptfds指向一个文件描述符集合的指针该集合中的文件描述符用于监视异常状态变化。timeout指向一个timeval结构的指针该结构指定了select函数的超时时间。如果设置为NULL则select会无限期地等待。 三、返回值
成功时select返回就绪的文件描述符的总数。如果超时返回0。如果出错返回-1并设置errno以指示错误。 四、文件描述符集合
fd_set是一个文件描述符集合它通常通过一系列宏来操作例如FD_ZERO、FD_SET、FD_CLR和FD_ISSET。这些宏定义在sys/select.h头文件中。 五、使用实例
以下是一个简单的select使用示例用于监视标准输入stdin的可读状态
#include stdio.h
#include stdlib.h
#include unistd.h
#include sys/types.h
#include sys/select.hint main(void) {fd_set readfds;struct timeval tv;int ret;// 初始化文件描述符集合FD_ZERO(readfds);FD_SET(STDIN_FILENO, readfds);// 设置超时时间为5秒tv.tv_sec 5;tv.tv_usec 0;// 调用select函数ret select(STDIN_FILENO 1, readfds, NULL, NULL, tv);if (ret -1) {perror(select error);exit(EXIT_FAILURE);} else if (ret 0) {printf(No data within 5 seconds.\n);} else {// 检查标准输入是否可读if (FD_ISSET(STDIN_FILENO, readfds)) {// 读取数据...// ...printf(Data is available on stdin.\n);}}return 0;
}六、select缺点
每次调用select, 都需要手动设置fd集合, 从接口使用角度来说也非常不便.每次调用select都需要把fd集合从用户态拷贝到内核态这个开销在fd很多时会很大同时每次调用select都需要在内核遍历传递进来的所有fd这个开销在fd很多时也很大select支持的文件描述符数量太小
七、总结
select函数是一个强大的工具允许程序同时监视多个文件描述符的状态变化。然而在处理大量文件描述符时select可能会遇到性能瓶颈因为它需要遍历所有被监视的文件描述符。在这种情况下更现代的替代品如poll和epoll可能更适合。不过对于许多常见的应用场景select仍然是一个简单而有效的解决方案。
select使用示例: 检测标准输入输出
#include stdio.h
#include unistd.h
#include sys/select.h
int main()
{fd_set read_fds;FD_ZERO(read_fds);FD_SET(0, read_fds);for (;;){printf( );fflush(stdout);int ret select(1, read_fds, NULL, NULL, NULL);if (ret 0){perror(select);continue;}if (FD_ISSET(0, read_fds)){char buf[1024] {0};read(0, buf, sizeof(buf) - 1);printf(input: %s, buf);}else{printf(error! invaild fd\n);continue;}FD_ZERO(read_fds);FD_SET(0, read_fds);}return 0;
}I/O多路转接之poll
poll函数
poll函数是Linux中用于I/O多路复用的系统调用之一类似于select函数但它在处理大量文件描述符时更加灵活和高效。以下是poll函数的详细用法介绍 一、函数声明
#include poll.hint poll(struct pollfd *fds, nfds_t nfds, int timeout);二、参数说明 fds指向pollfd结构数组的指针每个pollfd结构表示一个需要监视的文件描述符。 fd待监视的文件描述符。events指定要监视的事件类型如POLLIN数据可读、POLLOUT数据可写等。revents函数返回时表示实际发生的事件类型。 nfdsfds数组中的元素数量即要监视的文件描述符的数量。 timeout指定poll函数的超时时间以毫秒为单位。 -1表示poll调用将阻塞等待直到至少有一个文件描述符上发生事件。0表示poll调用将立即返回无论是否有文件描述符上发生事件。正整数表示poll调用将在指定的毫秒数内等待如果在此期间没有文件描述符上发生事件则超时返回。 三、返回值
正整数表示在指定时间内有多少个文件描述符上的事件已经就绪。0表示在指定的超时时间内没有任何文件描述符上的事件发生。-1表示函数调用失败此时会设置全局变量errno以指示错误。 四、使用步骤
创建一个pollfd结构数组并设置每个元素的fd和events字段。调用poll函数传入pollfd结构数组、数组长度和超时时间。检查poll函数的返回值以及每个pollfd结构的revents字段以确定哪些文件描述符上的事件已经就绪。根据需要处理就绪的文件描述符上的事件。 五、示例代码
以下是一个简单的示例代码展示了如何使用poll函数来监视标准输入stdin的可读状态
#include stdio.h
#include stdlib.h
#include unistd.h
#include string.h
#include poll.hint main(void) {struct pollfd fds[1];char buffer[1024];int n;// 初始化pollfd结构数组fds[0].fd STDIN_FILENO;fds[0].events POLLIN; // 监视可读事件// 调用poll函数设置超时时间为5秒int timeout 5000; // 5秒转换为毫秒n poll(fds, 1, timeout);if (n -1) {perror(poll error);exit(EXIT_FAILURE);} else if (n 0) {printf(No data within 5 seconds.\n);} else {// 检查标准输入是否可读if (fds[0].revents POLLIN) {// 读取数据ssize_t bytes_read read(STDIN_FILENO, buffer, sizeof(buffer) - 1);if (bytes_read 0) {buffer[bytes_read] \0; // 添加字符串终止符printf(Read %zd bytes: %s, bytes_read, buffer);} else {perror(read error);}}}return 0;
}六、总结
poll函数提供了一种高效的方式来监视多个文件描述符的状态变化。与select函数相比poll在处理大量文件描述符时更加灵活和高效因为它没有select函数中的文件描述符数量限制。然而对于非常大的文件描述符集合更现代的替代品如epoll可能更加适合。
poll示例: 使用poll监控标准输入
#include poll.h
#include unistd.h
#include stdio.h
int main()
{struct pollfd poll_fd;poll_fd.fd 0;poll_fd.events POLLIN;for (;;){int ret poll(poll_fd, 1, 5000);if (ret 0){perror(poll);continue;}if (ret 0){printf(poll timeout\n);continue;}if (poll_fd.revents POLLIN){char buf[1024] {0};read(0, buf, sizeof(buf) - 1);printf(stdin:%s, buf);}}
}I/O多路转接之epoll
简单介绍
I/O多路转接之epoll
epoll是Linux内核为处理大批量文件描述符而作的改进的poll是Linux下多路复用IO接口select/poll的增强版本。它能显著提高程序在大量并发连接中只有少量活跃的情况下的系统CPU利用率。以下是关于epoll的详细解释
一、epoll的特点和优势 高效性 相较于select和pollepoll使用了基于事件驱动的方式仅对活跃的文件描述符进行操作避免了线性扫描整个文件描述符集合因此效率更高。epoll通过内核与用户空间共享一个事件表当文件描述符的状态发生变化时内核会通知用户空间从而减少了不必要的系统调用。epoll支持边缘触发Edge Triggered模式使得用户空间程序有可能缓存IO状态减少epoll_wait/epoll_pwait的调用进一步提高应用程序效率。 无限制的文件描述符数量 select和poll有文件描述符数量的限制而epoll没有这样的限制仅受系统中进程能打开的最大文件数目限制。 内存使用优化 epoll使用mmap()文件映射内存加速内核与用户空间的消息传递避免了内核与用户空间之间的数据拷贝提高了效率。
二、epoll的接口和工作原理
epoll提供了三个主要的系统调用epoll_create()、epoll_ctl()和epoll_wait()。
epoll_create()创建一个epoll实例并返回一个文件描述符。epoll_ctl()用于向epoll实例中添加、修改或删除文件描述符的监视事件。epoll_wait()用于等待注册在epoll实例上的文件描述符的事件发生。当事件发生时epoll_wait()会返回并告知哪些文件描述符上的事件已经就绪。
epoll使用红黑树来管理待检测的文件描述符集合这使得在添加、删除和查找文件描述符时具有对数时间复杂度从而提高了效率。
三、epoll的使用场景
当需要同时监视多个文件描述符如sockets、文件、管道等上的事件并在有事件发生时通知应用程序进行相应的处理时epoll是一个非常好的选择。特别是在处理大量并发连接但只有少量活跃连接的情况下epoll的性能优势尤为明显。
四、总结
epoll作为Linux内核提供的一种高效的多路复用IO接口其特点在于高效性、无限制的文件描述符数量和内存使用优化。通过epoll可以方便地同时监视多个文件描述符上的事件并在事件发生时进行高效的处理。因此在高并发、低延迟的应用场景中epoll是一个值得考虑的解决方案。
epoll_create()、epoll_ctl()和epoll_wait()
当使用epoll进行I/O多路复用时主要涉及到三个系统调用epoll_create(), epoll_ctl(), 和 epoll_wait()。以下是这些函数的原型和参数解释 1. epoll_create()
函数原型
int epoll_create(int size);
int epoll_create1(int flags); // 这是 epoll_create 的一个扩展版本参数解释
size对于epoll_create这个参数是告诉内核这个监听的数目最大值。注意这个值只是内核初始分配内部数据结构的大小并不是限制。在Linux 2.6.8及以后的版本中这个参数被忽略但是为了代码的可移植性通常还是传递一个合适的大小值比如 1。flags对于epoll_create1这是一个位掩码用于修改epoll实例的行为。常用的标志有EPOLL_CLOEXEC当执行exec()函数时关闭文件描述符。
返回值
成功时返回一个非负整数即新的epoll文件描述符。失败时返回-1并设置全局变量errno以指示错误。
作用
创建一个新的epoll实例并返回一个文件描述符用于后续通过epoll_ctl()添加、修改或删除要监视的文件描述符以及通过epoll_wait()等待文件描述符上的事件。 2. epoll_ctl()
函数原型
int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);参数解释
epfd由epoll_create()或epoll_create1()返回的文件描述符。op操作码可以是以下三种之一 EPOLL_CTL_ADD注册新的文件描述符到epfd。EPOLL_CTL_MOD修改已经注册的文件描述符的监听事件。EPOLL_CTL_DEL从epfd中注销一个文件描述符。 fd需要添加、修改或删除的文件描述符。event指向epoll_event结构的指针描述了要监听的事件和与之关联的数据。
返回值
成功时返回0。失败时返回-1并设置全局变量errno以指示错误。
作用
用于向epoll实例中添加、修改或删除要监视的文件描述符及其相关的事件。 3. epoll_wait()
函数原型
int epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout);参数解释
epfd由epoll_create()或epoll_create1()返回的文件描述符。events指向epoll_event结构数组的指针用于存储从内核返回的事件。maxevents告诉内核这个events数组有多大这个值不能大于创建epoll_create时的size。timeout等待超时时间毫秒-1 表示永远等待。
返回值
成功时返回发生事件的文件描述符的数量这些事件被存储在events数组中。如果在timeout毫秒内没有事件发生返回0。失败时返回-1并设置全局变量errno以指示错误。
作用
等待在epfd上注册的文件描述符上的事件。当这些事件中的任何一个发生时epoll_wait()将返回并将所有触发的事件存储在events数组中。
注意在使用epoll时还需要了解epoll_event结构体它描述了注册到epoll实例中的事件和与之关联的数据。这个结构体通常包含两个成员events表示要监听的事件类型和data用户定义的数据通常用于在事件触发时识别是哪个文件描述符触发了事件。
epoll_event结构体
epoll_event 结构体是 epoll 机制中用于注册、修改和接收文件描述符上事件的重要数据结构。它定义在 sys/epoll.h 头文件中并用于 epoll_ctl() 函数中注册感兴趣的事件和 epoll_wait() 函数中接收已触发的事件。
epoll_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当相应的文件描述符可读时触发。EPOLLOUT当相应的文件描述符可写时触发。EPOLLPRI当相应的文件描述符有优先读取数据可读时触发不常用。EPOLLERR当相应的文件描述符发生错误时触发。EPOLLHUP当相应的文件描述符被挂起时触发如 TCP 连接被对方关闭。EPOLLET设置文件描述符为边缘触发Edge Triggered模式。默认是水平触发Level Triggered模式。以及其他一些不太常用的事件。 data 这是一个联合体允许用户关联任意类型的数据到事件上。这样当事件触发时你可以通过这个联合体来识别是哪个文件描述符触发了事件。 ptr一个指向任意类型数据的指针。fd一个文件描述符。这通常用于存储与事件关联的文件描述符但请注意这与 epoll_event 结构体中的 events 成员中引用的文件描述符不同。u32 和 u64无符号的 32 位和 64 位整数。你可以使用这些字段来存储自定义的整数数据。 使用方法
在 epoll_ctl() 调用中你会创建一个 epoll_event 结构体实例并设置其 events 成员为你感兴趣的事件类型以及 data 成员为你想要关联的数据。然后你将这个结构体的指针传递给 epoll_ctl()。
在 epoll_wait() 调用中你会传递一个 epoll_event 结构体数组以及它的大小给该函数。当 epoll_wait() 返回时它会更新这个数组中的 epoll_event 结构体实例以反映实际触发的事件。然后你可以遍历这个数组检查每个 epoll_event 结构体的 events 成员来确定哪些事件被触发了并使用 data 成员来获取与事件关联的数据。
epoll示例: 使用epoll监控标准输入
为了使用epoll来监控标准输入通常是文件描述符0即stdin我们可以编写一个简单的程序来演示epoll_create(), epoll_ctl(), 和 epoll_wait() 的使用。以下是一个简单的C程序示例
#include stdio.h
#include stdlib.h
#include unistd.h
#include string.h
#include errno.h
#include sys/epoll.h#define MAX_EVENTS 10int main(void) {int epfd, nfds;struct epoll_event ev, events[MAX_EVENTS];// 创建一个 epoll 实例epfd epoll_create1(0);if (epfd -1) {perror(epoll_create1);exit(EXIT_FAILURE);}// 配置要监控的事件ev.events EPOLLIN; // 监听可读事件ev.data.fd STDIN_FILENO; // 标准输入的文件描述符// 向 epoll 实例添加监控的文件描述符if (epoll_ctl(epfd, EPOLL_CTL_ADD, STDIN_FILENO, ev) -1) {perror(epoll_ctl: add);exit(EXIT_FAILURE);}// 等待事件发生for (;;) {nfds epoll_wait(epfd, events, MAX_EVENTS, -1); // 阻塞等待if (nfds -1) {perror(epoll_wait);break;}// 遍历所有触发的事件for (int n 0; n nfds; n) {if (events[n].data.fd STDIN_FILENO) {// 读取标准输入char buffer[1024];ssize_t bytes_read read(STDIN_FILENO, buffer, sizeof(buffer) - 1);if (bytes_read 0) {// 去掉换行符并打印buffer[bytes_read] \0;char *newline strchr(buffer, \n);if (newline) *newline \0;printf(Read from stdin: %s\n, buffer);} else if (bytes_read 0) {printf(EOF reached on stdin\n);break;} else {perror(read);break;}}}}// 关闭 epoll 文件描述符close(epfd);return 0;
}在这个程序中我们首先使用epoll_create1()创建一个epoll实例。然后我们使用epoll_ctl()添加一个事件来监听标准输入stdin的可读事件。在无限循环中我们使用epoll_wait()等待事件发生。当标准输入上有数据可读时我们读取这些数据并打印出来。如果读取到文件结束符EOF或者读取操作失败我们退出循环。最后我们关闭epoll文件描述符并退出程序。 如上便是本期的所有内容了如果喜欢并觉得有帮助的话希望可以博个点赞收藏关注❤️ ,学海无涯苦作舟,愿与君一起共勉成长