网站跳出率计算,美食网站网页设计代码,网络推广公司如何做,跨境电商app下载1、阻塞IO和非阻塞IO
1.1 阻塞IO - 在阻塞IO模型中#xff0c;当一个IO操作#xff08;如读取或写入#xff09;开始时#xff0c;如果数据没有准备好#xff0c;程序会被挂起#xff08;即阻塞#xff09;#xff0c;直到数据准备好并且IO操作完成。 - 在数据准备阶段…1、阻塞IO和非阻塞IO
1.1 阻塞IO - 在阻塞IO模型中当一个IO操作如读取或写入开始时如果数据没有准备好程序会被挂起即阻塞直到数据准备好并且IO操作完成。 - 在数据准备阶段程序做不了其他事情它会等待在那里直到整个IO操作完全完成后才会继续执行。 - 阻塞IO简化了编程模型因为在发起IO请求之后你只需要等待结果不必担心在这个过程中如何处理其他任务。 1.2 非阻塞IO - 非阻塞IO模型中IO操作不会导致程序挂起等待。如果数据没有准备好IO调用会立即返回一个指示数据尚未准备好的状态。 - 程序可以继续执行后续代码它可以定期地检查IO操作是否可以进行或者可以进行其他工作这样很好地利用了等待时间。该过程称为 polling 。 - 非阻塞IO通常与事件驱动或轮询机制一起使用程序可以在多个IO操作之间有效地切换提高了程序的整体效率和响应性。 非阻塞IO更适用于处理高并发情况尤其在需要同时管理多个连接或者进行多个并行IO操作时。但这种模型编程难度较高因为要管理和调度多个IO操作而且可能需要额外的机制如IO复用或事件通知来检测IO状态。 1.3 如何将阻塞IO更改成非阻塞IO #include unistd.h #include fcntl.h int fcntl(int fd, int cmd, ... /* arg */ ); 功能获取或者设置当前文件描述符的属性和状态是哪一种操作取决于cmd fd要处理的文件描述符 cmd: 要执行的操作 F_GETFL: 获取文件描述符的属性第三个参数可以忽略 F_SETFL设置文件描述符的属性第三个参数为int 是否设置参数3取决于参数2如果参数2为 F_SETFL参数3就是为当前文件描述符设置的值 返回值取决于cmd 如果cmd 为F_GETFL则成功返回当前文件描述符的属性值失败返回-1并置位错误码 如果cmd 为 F_SETFL则成功返回0失败返回-1并置位错误码 步骤 1、先获取当前文件描述符的属性 int flag fcntl(fd, F_GETFL); 2、将当前的文件描述符的属性中添加非阻塞属性 flag | O_NONBLOCK; 3、将更改后的状态加到当前文件描述符中 fcntl(fd, F_SETFL, flag); int main(int argc, const char *argv[])
{int num 0;//1、获取当前文件描述的属性int flag fcntl(0, F_GETFL);//2、给当前的文件描述符加上非阻塞属性flag | O_NONBLOCK;//3、再将新属性设置回去fcntl(0, F_SETFL, flag);while(1){printf(请输入);scanf(%d, num);//此处省略一万行代码printf(num %d\n, num);}return 0;
}2、IO多路复用
2.1 IO多路复用的相关概念 1、如果程序中需要同时处理多个阻塞任务时在使用单进程或单线程的情况下可以处理多个阻塞任务 2、在无法使用多进程或多线程时还想完成多任务并发此时可以使用IO多路复用技术 3、优点由于不需要多进程或多线程能够有效减少系统的资源开销减少上下文切换的次数效率较高 4、原理图 2.2 select #include sys/select.h int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout); 功能阻塞等待检测容器中是否有事件产生如果有一个或多个事件产生则解除阻塞并且将没有产生事件的文件描述符从集合中清除 参数1检测集合中最大的文件描述符的值 1 参数2、3、4分别是读、写、异常检测的文件描述符集合如果不用可以填NULL 参数5超时时间可以是如下的结构体变量的地址也可以填NULL表示永久等待 struct timeval { long tv_sec; /* seconds */ long tv_usec; /* microseconds */ }; and struct timespec { long tv_sec; /* seconds */ long tv_nsec; /* nanoseconds */ }; 返回值 0 表示本次解除阻塞触发事件的文件描述符总个数 0 表示设置的超时时间并超时时间内没有事件产生 -1 出错置位错误码 四个宏函数用于对文件描述符集合的操作 void FD_CLR(int fd, fd_set *set); // 将fd文件描述符从集合set中移除 int FD_ISSET(int fd, fd_set *set); // 判断fd文件描述符是否存在于set集合中 void FD_SET(int fd, fd_set *set); // 将fd文件描述符添加到set集合中 void FD_ZERO(fd_set *set); // 将set文件描述符集合清空 使用select实现TCP并发服务器--框架 int main(){ sfd socket(); // 创建用于连接的套接字 bind(); // 绑定ip和端口号 listen(); // 将套接字设置成被动监听状态 fd_set readfds, tempfds; FD_ZERO(readfds) FD_SET(sfd, readfds); int max sfd; while(1){ tempfds readfds; select(max1, tempfds, NULL, NULL,NULL); //阻塞检测集合中文件描述符 是否有事件产生 for(int i 0; i max; i){ if(!FD_ISSET(i, tempfds)){ continue; } if(i sfd){ newfd accept() FD_SETnewfd readfds ); max max newfd ? max : newfd; }else{ recv() send() 下线关闭close(i) FD_CLR(i, readfds); //更新max for(j max; j sfd; j--){ if(FD_ISSET(j, tempfds)){ max j; } } } } } close(sfd); } 2.3 poll #include poll.h int poll(struct pollfd *fds, nfds_t nfds, int timeout); 功能阻塞等待文件描述符集合中是否有事件产生如果有事件产生则解除阻塞 参数1文件描述符集合数组是一个结构体数组 struct pollfd { int fd; /* 要检测的文件描述符 */ short events; /* 要检测的事件 */ short revents; /* 真实发生的事件 */ 该值无需初始化poll函数会给 该参数赋值 }; 常用事件种类 POLLIN读事件 POLLOUT写事件 参数2集合中文件描述符的个数 参数3以毫秒为单位的超时时间 0: 表示设置的超时时间 0 表示非阻塞 0: 表示永久阻塞 返回值 0: 表示返回解除阻塞的事件对应的文件描述符个数 0: 表示超时 0: 失败置位错误码 poll完成TCP客户端中发送数据和接收数据的并发执行 int main(){ cfd socket(); bind() connect(); // 使用poll 完成 多阻塞任务的并发 struct pollfd pfd[2]; // 定义一个2长度的结构体数组 pfd[0].fd 0; // 表示检测0号stdin文件描述符 pfd[0].events POLLIN; // 表示检测读事件 pfd[1].fd cfd; // 表示检测cfd文件描述符 pfd[1].events POLLIN; // 表示检测读事件 while(1){ int res poll(pfd, 2, -1); if (res -1){ perror(poll error); return -1; }else if (res 0){ printf(time out\n); return -1; } //判断是否为0号文件描述符产生的事件 if(pfd[0].revents POLLIN){ } //判断是否为cfd文件描述符产生事件 if(pfd[1].revents POLLIN){ recv() } } close(cfd) return 0; }