io多路复用之poll的详细执行过程

简介: io多路复用之poll的详细执行过程

1.结构体struct pollfd的定义

struct pollfd {

   int   fd;        /* 文件描述符 */

   short events;    /* 想要监视的事件(input/output/priority) */

   short revents;   /* 实际发生的事件(返回的事件) */

};

2.定义pollfd数组,并设置listenfd想要监听的事件

struct pollfd fds[POLL_SIZE]={0};//定义一个POLL_SIZE大小的pollfd数组
    fds[sockfd].fd=sockfd;
    fds[sockfd].events=POLLIN;//设置想要监听的事件为POLLIN

3.调用函数poll()监听事件的发生,并返回实际发生的事件

int nready=poll(fds,maxfd+1,-1);
printf("nready:%d\n",nready);//实际发生的事件的数量

int poll(struct pollfd *fds, nfds_t nfds, int timeout);
fds:一个指向 struct pollfd 结构体数组的指针,每个结构体描述了一个要监视的文件描述符及其关联的事件和发生的事件

nfds:表示文件描述符数组 fds 的大小,即要监视的文件描述符的数量。

timeout:超时值,指定 poll() 函数的阻塞时间。它可以有以下几种取值:

  • 传递负数:表示无限阻塞,poll() 函数将一直等待,直到至少一个文件描述符的事件发生。
  • 传递0:表示非阻塞模式,poll() 函数会立即返回,不管文件描述符的状态如何。
  • 传递正整数:表示超时时间(以毫秒为单位),poll() 函数会等待指定的毫秒数后返回,如果在超时前没有任何事件发生,它将返回0

注意:poll的返回值并不是clientfd(客户端)连接注册想要监听的事件,而是在这些已注册监听事件中实际发生的事件的个数.

4.判断revent数值

在调用 poll 函数后,revents 字段会被设置为实际发生的事件。revents 字段是一个位掩码,它可以包含以下几个值中的一个或多个,表示文件描述符的状态:

  • POLLIN:文件描述符可以进行读取操作。
  • POLLOUT:文件描述符可以进行写入操作。
  • POLLERR:文件描述符发生了错误。
  • POLLHUP:文件描述符挂起(连接关闭)。
  • POLLNVAL:文件描述符无效。

如果要检查文件描述符是否可以读取,可以执行以下操作:

if (revents & POLLIN) {
    // 文件描述符可以进行读取操作
}

只有当被监听的事件实际发生时才会执行

demo:

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<fcntl.h>
#include<poll.h>
#define PORT 8848
#define POLL_SIZE 1024
#define BUFLEN 128
int main(){
    int sockfd=socket(AF_INET,SOCK_STREAM,0);
    struct sockaddr_in serveraddr;
    memset(&serveraddr,0,sizeof(struct sockaddr_in));
    serveraddr.sin_family=AF_INET;
    serveraddr.sin_port=htons(PORT);
    serveraddr.sin_addr.s_addr=htonl(INADDR_ANY);
    if(-1==bind(sockfd,(struct sockaddr*)&serveraddr,sizeof(serveraddr))){
        printf("bind failed\n");
        exit(1);
    }
    listen(sockfd,10);
    //poll
    /*
    struct pollfd {
        int   fd;        //文件描述符 
        short events;    // 想要监视的事件(input/output/priority) 
        short revents;   // 实际发生的事件(返回的事件) 
    };
    */
    struct pollfd fds[POLL_SIZE]={0};
    fds[sockfd].fd=sockfd;
    fds[sockfd].events=POLLIN;
    int maxfd=sockfd;
    int clientfd=0;
    int count=0;
    while(1){
        printf("count:%d\n",count++);//打印while循环次数
        //sleep(10);//休眠10s
        int nready=poll(fds,maxfd+1,-1);
        printf("nready:%d\n",nready);//实际发生的事件的数量
        //revent
        if(fds[sockfd].revents&POLLIN){
            struct sockaddr_in clientaddr;
            socklen_t len=sizeof(clientaddr);
            clientfd=accept(sockfd,(struct sockaddr*)&clientaddr,&len);
            printf("new client:%d\n",clientfd);
            fds[clientfd].fd=clientfd;
            fds[clientfd].events=POLLIN;
            if(clientfd>maxfd){
                maxfd=clientfd;
            }
            if(nready-1==0){
                continue;
            }
        }
        int i=sockfd+1;
        for(;i<=maxfd;i++){
            char buffer[BUFLEN]={0};
            int ret=0;
            if(fds[i].revents&POLLIN){//只有事件实际发生时,该if程序才会被执行
                ret=read(fds[i].fd,buffer,BUFLEN-1);
                if(ret==0){//客户端主动关闭
                    printf("client %d close\n",fds[i].fd);
                    close(fds[i].fd);//关闭socket
                    //重置
                    fds[i].fd=-1;
                    fds[i].events=0;
                    continue;
                }
                buffer[ret]='\0';
                printf("recv from client:%d  buffer:%s\n",fds[i].fd,buffer);
                ret=write(fds[i].fd,buffer,strlen(buffer));
            }
        }
    }
    exit(0);
}
目录
相关文章
|
1月前
|
存储 监控 Linux
【Linux IO多路复用 】 Linux下select函数全解析:驾驭I-O复用的高效之道
【Linux IO多路复用 】 Linux下select函数全解析:驾驭I-O复用的高效之道
54 0
|
3月前
|
存储 Linux 调度
io复用之epoll核心源码剖析
epoll底层实现中有两个关键的数据结构,一个是eventpoll另一个是epitem,其中eventpoll中有两个成员变量分别是rbr和rdlist,前者指向一颗红黑树的根,后者指向双向链表的头。而epitem则是红黑树节点和双向链表节点的综合体,也就是说epitem即可作为树的节点,又可以作为链表的节点,并且epitem中包含着用户注册的事件。当用户调用epoll_create()时,会创建eventpoll对象(包含一个红黑树和一个双链表);
72 0
io复用之epoll核心源码剖析
|
3月前
|
存储 网络协议
TCP服务器 IO多路复用的实现:select、poll、epoll
TCP服务器 IO多路复用的实现:select、poll、epoll
36 0
|
3月前
|
网络协议 Linux C++
Linux C/C++ 开发(学习笔记十二 ):TCP服务器(并发网络编程io多路复用epoll)
Linux C/C++ 开发(学习笔记十二 ):TCP服务器(并发网络编程io多路复用epoll)
59 0
|
1月前
|
NoSQL Java Linux
【Linux IO多路复用 】 Linux 网络编程 认知负荷与Epoll:高性能I-O多路复用的实现与优化
【Linux IO多路复用 】 Linux 网络编程 认知负荷与Epoll:高性能I-O多路复用的实现与优化
64 0
|
1月前
|
JavaScript Unix Linux
IO多路复用:提高网络应用性能的利器
IO多路复用:提高网络应用性能的利器
|
3月前
|
网络协议 架构师 Linux
一文说透IO多路复用select/poll/epoll
一文说透IO多路复用select/poll/epoll
160 0
|
3月前
|
网络协议 Linux
2.1.1网络io与io多路复用select/poll/epoll
2.1.1网络io与io多路复用select/poll/epoll
|
1月前
|
存储 Java 数据处理
|
1月前
|
Java API
java中IO与NIO有什么不同
java中IO与NIO有什么不同