多路I/O复用——poll

1.select的缺点
①监听文件描述符受限制,最大是1024
②每次都要从0开始遍历文件描述符,效率低,需要自己增加满足条件的文件描述符数组提高效率,但增加了编码难度
但select是对路/O转接中唯一支持跨平台的,win、linux等
2.poll的优点
在select的基础上,自己定义了数组结构,可以将监听事件和返回事件集合分离,拓展了监听上限,可以超出1024的限制,但是poll不能实现跨平台操作
3.poll函数

int poll(struct pollfd *fds, nfds_t nfds, int timeout)

fds:监听文件描述符的数组,加上*表示对数组取地址
struct polled{
int fd; //待监听的文件描述符
short events; //待监听的文件描述符对应的事件
POLLIN、POLLOUT、POLLERR
short revents; //传入时,给0;如果有对应事件满足的话,返回非0;
}
nfds:监听数组的实际有效监听个数
timeout:超时时长,单位为毫秒
-1:阻塞等待
0:立即返回,不阻塞
>0:等待的时长
返回值:返回满足对应监听事件的文件描述符总个数
3.原理分析
首先,要定义一个struct polled类型的数组,将监听描述符初始化到数组中,调用poll函数后,分别对监听事件和读写事件进行判断,有监听事件满足则将accept()返回的cfd加入数组中,有读写事件满足则完成读写操作

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<arpa/inet.h>
#include<netinet/in.h>
#include<poll.h>
#include<ctype.h>

#define SERV_PORT 6666
#define OPEN_MAX 1024

int main()
{
    int i, j, n;
    int lfd, cfd;
    char buf[BUFSIZ], str[INET_ADDRSTRLEN];    //INET_ADDRSTRLEN是16
    struct sockaddr_in clie_addr, serv_addr;
    socklen_t clie_addr_len;
    lfd = socket(AF_INET, SOCK_STREAM, 0);
    int opt = 1;
    setsockopt(lfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(serv_addr));  //设置端口复用
    bzero(&serv_addr, sizeof(serv_addr));    //定义服务器地址结构
    serv_addr.sin_family = AF_INET;
    serv_addr.sin_port = htons(SERV_PORT);
    serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
    bind(lfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr));
    listen(lfd, 128);

    struct pollfd client[OPEN_MAX];     //创建polled类型的数组
    client[0].fd = lfd;                 //将监听文件描述符放入监听序列
    client[0].events = POLLIN;

    for(i=1; i<OPEN_MAX; i++){
        client[i].fd = -1;
    }

    int maxfd = 0, ret;

    while(1){
        ret = poll(client, maxfd+1, -1);    //阻塞监听是否有事件满足
        if(ret>0){
            if(client[0].revents & POLLIN){     //监听到有读事件满足
                clie_addr_len = sizeodf(clie_addr);
                cfd = accept(lfd, (struct sockaddr *)&clie_addr, &clie_addr_len);
                for(i=1; i<OPEN_MAX; i++){
                    if(client[i].fd<0){
                        client[i].fd = cfd;
                        break;
                    }
                    if(i==OPEN_MAX){
                        exit(0);
                    }
                    if(maxfd<i){
                        maxfd = i;
                    }
                    if(--ret==0)   //select传出只有lfd,无需后续执行
                        continue;
                }
                
            }
            for(i=1; i<=maxfd; i++){
                if(client[i].fd<0){
                    continue;        //出错
                }
                if(client[i].event & POLLIN){
                    n = read(i, buf, sizeof(buf));
                    if(n<0){
                        exit(0);
                    }
                    if(n==0){
                        close(i);
                        client[i].fd = -1;   //监听的该文件描述符结束操作,还原回-1
                    }
                    for(j=0; j<n; j++){
                        buf[j] = toupper(buf[j]);
                    }
                    write(i, buf, n);
                    write(STD_OUT, buf, n);
                    if(--ret==0)   //poll传出只有cfd,无需后续执行
                        continue;
                }
                
            }
        }
    }
    close(lfd);
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值