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);
}
目录
相关文章
|
2月前
|
网络协议 安全 Linux
Linux C/C++之IO多路复用(select)
这篇文章主要介绍了TCP的三次握手和四次挥手过程,TCP与UDP的区别,以及如何使用select函数实现IO多路复用,包括服务器监听多个客户端连接和简单聊天室场景的应用示例。
95 0
|
2月前
|
存储 Linux C语言
Linux C/C++之IO多路复用(aio)
这篇文章介绍了Linux中IO多路复用技术epoll和异步IO技术aio的区别、执行过程、编程模型以及具体的编程实现方式。
95 1
Linux C/C++之IO多路复用(aio)
|
2月前
|
Linux C++
Linux C/C++之IO多路复用(poll,epoll)
这篇文章详细介绍了Linux下C/C++编程中IO多路复用的两种机制:poll和epoll,包括它们的比较、编程模型、函数原型以及如何使用这些机制实现服务器端和客户端之间的多个连接。
32 0
Linux C/C++之IO多路复用(poll,epoll)
|
2月前
|
Java Linux
【网络】高并发场景处理:线程池和IO多路复用
【网络】高并发场景处理:线程池和IO多路复用
50 2
|
2月前
|
监控 网络协议 Java
IO 多路复用? 什么是 IO 多路复用? 简单示例(日常生活)来解释 IO 多路复用 一看就懂! 大白话,可爱式(傻瓜式)教学! 保你懂!
本文通过日常生活中的简单示例解释了IO多路复用的概念,即一个线程通过监控多个socket来处理多个客户端请求,提高了效率,同时介绍了Linux系统中的select、poll和epoll三种IO多路复用的API。
142 2
|
3月前
|
消息中间件 NoSQL Java
面试官:谈谈你对IO多路复用的理解?
面试官:谈谈你对IO多路复用的理解?
51 0
面试官:谈谈你对IO多路复用的理解?
|
3月前
|
网络协议 Java Linux
高并发编程必备知识IO多路复用技术select,poll讲解
高并发编程必备知识IO多路复用技术select,poll讲解
|
5月前
|
存储 Java Unix
(八)Java网络编程之IO模型篇-内核Select、Poll、Epoll多路复用函数源码深度历险!
select/poll、epoll这些词汇相信诸位都不陌生,因为在Redis/Nginx/Netty等一些高性能技术栈的底层原理中,大家应该都见过它们的身影,接下来重点讲解这块内容。
|
5月前
stm32f407探索者开发板(十四)——IO引脚复用和映射
stm32f407探索者开发板(十四)——IO引脚复用和映射
488 0
|
4月前
|
存储 Java
【IO面试题 四】、介绍一下Java的序列化与反序列化
Java的序列化与反序列化允许对象通过实现Serializable接口转换成字节序列并存储或传输,之后可以通过ObjectInputStream和ObjectOutputStream的方法将这些字节序列恢复成对象。