做钢材的网站有哪些,杭州公司展厅设计公司,正能量网站免费入口不用下载,九亭网站建设https://blog.csdn.net/lianghe_work/article/details/46534029一、回顾前面的selectselect优点#xff1a;目前几乎在所有的平台上支持#xff0c;其良好跨平台支持也是它的一个优点select缺点#xff1a;1.每次调用 select()#xff0c;都需要把 fd 集合从用户态拷贝到内…https://blog.csdn.net/lianghe_work/article/details/46534029一、回顾前面的select
select优点目前几乎在所有的平台上支持其良好跨平台支持也是它的一个优点select缺点1.每次调用 select()都需要把 fd 集合从用户态拷贝到内核态这个开销在 fd 很多时会很大同时每次调用 select() 都需要在内核遍历传递进来的所有 fd这个开销在 fd 很多时也很大。2.单个进程能够监视的文件描述符的数量存在最大限制在 Linux 上一般为 1024可以通过修改宏定义甚至重新编译内核的方式提升这一限制但是这样也会造成效率的降低二、poll函数概述
select() 和 poll() 系统调用的本质一样poll() 的机制与 select() 类似与 select() 在本质上没有多大差别管理多个描述符也是进行轮询根据描述符的状态进行处理但是 poll() 没有最大文件描述符数量的限制但是数量过大后性能也是会下降。poll() 和 select() 同样存在一个缺点就是包含大量文件描述符的数组被整体复制于用户态和内核的地址空间之间而不论这些文件描述符是否就绪它的开销随着文件描述符数量的增加而线性增大。poll()函数介绍头文件#include poll.h函数体int poll(struct pollfd *fds, nfds_t nfds, int timeout);功能监视并等待多个文件描述符的属性变化参数fds:指向一个结构体数组的第0个元素的指针每个数组元素都是一个struct pollfd结构用于指定测试某个给定的fd的条件struct pollfd{ int fd; //文件描述符 short events; //等待的事件 short revents; //实际发生的事件};fd每一个 pollfd 结构体指定了一个被监视的文件描述符可以传递多个结构体指示 poll() 监视多个文件描述符。events指定监测fd的事件输入、输出、错误每一个事件有多个取值如下reventsrevents 域是文件描述符的操作结果事件内核在调用返回时设置这个域。events 域中请求的任何事件都可能在 revents 域中返回.注意每个结构体的 events 域是由用户来设置告诉内核我们关注的是什么而 revents 域是返回时内核设置的以说明对该描述符发生了什么事件nfds:用来指定第一个参数数组元素个数timeout: 指定等待的毫秒数无论 I/O 是否准备好poll() 都会返回.返回值成功时poll() 返回结构体中 revents 域不为 0 的文件描述符个数如果在超时前没有任何事件发生poll()返回 0失败时poll() 返回 -1并设置 errno 为下列值之一EBADF一个或多个结构体中指定的文件描述符无效。EFAULTfds 指针指向的地址超出进程的地址空间。EINTR请求的事件之前产生一个信号调用可以重新发起。EINVALnfds 参数超出 PLIMIT_NOFILE 值。ENOMEM可用内存不足无法完成请求。三、poll示例举例
用poll实现udp同时收发代码#include string.h#include stdio.h#include stdlib.h#include unistd.h#include sys/select.h#include sys/time.h#include sys/socket.h#include netinet/in.h#include arpa/inet.h#include poll.h int main(int argc,char *argv[]){ int udpfd 0; int ret 0; struct pollfd fds[2];//监测文件描述结构体数组2个 struct sockaddr_in saddr; struct sockaddr_in caddr; bzero(saddr,sizeof(saddr));saddr.sin_family AF_INET;saddr.sin_port htons(8000);saddr.sin_addr.s_addr htonl(INADDR_ANY); bzero(caddr,sizeof(caddr));caddr.sin_family AF_INET;caddr.sin_port htons(8000); //创建套接字 if( (udpfd socket(AF_INET,SOCK_DGRAM, 0)) 0){perror(socket error);exit(-1);} //套接字端口绑字 if(bind(udpfd, (struct sockaddr*)saddr, sizeof(saddr)) ! 0){perror(bind error);close(udpfd); exit(-1);} printf(input: \sayto 192.168.220.X\ to sendmsg to somebody\033[32m\n); fds[0].fd 0; //标准输入描述符fds[1].fd udpfd; //udp描述符 fds[0].events POLLIN; // 普通或优先级带数据可读 fds[1].events POLLIN; // 普通或优先级带数据可读 while(1){ // 监视并等待多个文件标准输入udp套接字描述符的属性变化是否可读 // 没有属性变化这个函数会阻塞直到有变化才往下执行这里没有设置超时 ret poll(fds, 2, -1); write(1,UdpQQ:,6); if(ret -1){ // 出错 perror(poll()); } else if(ret 0){ // 准备就绪的文件描述符 char buf[100] {0}; if( ( fds[0].revents POLLIN ) POLLIN ){ // 标准输入 fgets(buf, sizeof(buf), stdin);buf[strlen(buf) - 1] \0; if(strncmp(buf, sayto, 5) 0){ char ipbuf[16] ;inet_pton(AF_INET, buf6, caddr.sin_addr);//给addr套接字地址再赋值.printf(\rsay to %s\n,inet_ntop(AF_INET,caddr.sin_addr,ipbuf,sizeof(ipbuf))); continue;} else if(strcmp(buf, exit)0){close(udpfd);exit(0);}sendto(udpfd, buf, strlen(buf),0,(struct sockaddr*)caddr, sizeof(caddr)); } else if( ( fds[1].revents POLLIN ) POLLIN ){ //udp套接字 struct sockaddr_in addr; char ipbuf[INET_ADDRSTRLEN] ;socklen_t addrlen sizeof(addr); bzero(addr,sizeof(addr)); recvfrom(udpfd, buf, 100, 0, (struct sockaddr*)addr, addrlen);printf(\r\033[31m[%s]:\033[32m%s\n,inet_ntop(AF_INET,addr.sin_addr,ipbuf,sizeof(ipbuf)),buf); } } else if(0 ret){ // 超时 printf(time out\n); } } return 0;} 运行结果