高级IO——IO多路转接之poll

poll是Linux中的字符设备驱动中的一个函数。和select实现的功能差不多,poll的作用是把当前的文件指针挂到等待队列。



参数说明:

fd是一个poll函数监听的结构列表。每一个元素中,包含了三部分内容:文件描述符、监听的事件集合、返回的事件集合;

nfds表示fds数组的长度;

timeout表示poll函数的超时时间,单位是毫秒(ms)。

events和revents的取值:


返回结果:

    (1)返回值小于0,表示出错;

    (2)返回值等于0,表示poll函数等待超时;

    (3)返回值大于0,表示poll由于监听的文件描述符就绪而返回。


  • poll的优点

不同于select使用三个位图来表示三个fdset的方式,poll使用一个pollfd的指针实现

poll结构包含了要监视的event和要发生的event,不再使用select“参数——值”传递的方式,接口使用比select更方便。

poll并没有最大数量限制,但是数量过大后性能还是会下降。

  • poll的缺点

poll中监听的文件描述符数目增多时:

    (1)和select函数一样,poll返回后,需要轮询pollfd来获取就绪的描述符;

    (2)每次调用poll都需要把大量的pollfd结构从用户态拷贝到内核态;

    (3)同时连接的大量客户端在一时刻可能只有很少的处于就绪状态,因此随着监视的描述符的数量的增长,其效率也会线性下降。


  • 多路转接服务器
服务器端:
#include <stdio.h>
#include<unistd.h>
#include<poll.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<stdlib.h>
#include<string.h>

typedef struct pollfd pollfd;


void Init(pollfd* fd_list,int size){
    int i = 0;
    for(i = 0;i < size;i++){
        fd_list[i].fd = -1;
        fd_list[i].events = 0; 
        fd_list[i].revents = 0;
    }
}

void Add(int fd,pollfd* fd_list,int size){
    int i = 0;
    for(i = 0;i < size;i++){
        if(fd_list[i].fd == -1){
            fd_list[i].fd = fd;
            fd_list[i].events = POLLIN;
            break;
        }
    }
}

int main(int argc,char* argv[]){
    if(argc != 3){
        printf("Usage ./server [ip] [port]\n");
        return 1;
    }
    struct sockaddr_in addr;
    addr.sin_family = AF_INET;
    addr.sin_addr.s_addr = inet_addr(argv[1]);
    addr.sin_port = htons(atoi(argv[2]));

    int listen_fd = socket(AF_INET,SOCK_STREAM,0);
    if(listen_fd < 0){
        perror("socket");
        return 2;
    }

    int ret = bind(listen_fd,(struct sockaddr*)&addr,sizeof(addr));
    if(ret < 0){
        perror("bind");
        return 3;
    }
    ret = listen(listen_fd,5);
    if(ret < 0){
        perror("listen");
        return 4;
    }
    pollfd fd_list[1024];
    Init(fd_list,sizeof(fd_list)/sizeof(pollfd));
    Add(listen_fd,fd_list,sizeof(fd_list)/sizeof(pollfd));
    for(;;){
        int ret = poll(fd_list,sizeof(fd_list)/sizeof(pollfd),1000);
        if(ret < 0){
            perror("poll");
            continue;
        }
        if(ret == 0){
            printf("poll timeout\n");
            continue;
        }
        size_t i = 0;
        for(i = 0;i < sizeof(fd_list)/sizeof(pollfd);i++){
            if(fd_list[i].fd == -1)
                continue;
            if(! (fd_list[i].revents & POLLIN))
                continue;
            if(fd_list[i].fd == listen_fd){
                struct sockaddr_in client_addr;
                socklen_t len = sizeof(client_addr);
                int connect_fd = accept(listen_fd,(struct sockaddr*)&client_addr,&len);
                if(connect_fd < 0){
                    perror("accept");
                    continue;
                }
                Add(connect_fd,fd_list,sizeof(fd_list)/sizeof(pollfd));
            }
            else{
                char buf[1024] = {0};
                ssize_t read_size = read(fd_list[i].fd,buf,sizeof(buf)-1);
                if(read_size < 0){
                    perror("read");
                    continue;
                }
                if(read_size == 0){
                    printf("client say:stop...\n");
                    close(fd_list[i].fd);
                    fd_list[i].fd = -1;
                }
                printf("client say:%s\n",buf);
                write(fd_list[i].fd,buf,strlen(buf));
            }
        }
    }
    return 0;
}

客户端:

#include <stdio.h>  
#include<sys/socket.h>  
#include<netinet/in.h>  
#include<unistd.h>  
#include<string.h>  
#include<arpa/inet.h>
#include<sys/types.h>  
#include<stdlib.h>  
#include<string.h>  
  
#define MAX 128  
  
int main(int argc,char* argv[]){  
    if(argc != 3){  
            printf("Usage:%s [ip] [port]\n",argv[0]);  
            return 1;  
        }  
    int sock = socket(AF_INET,SOCK_STREAM,0);  
    if(sock < 0){  
            printf("socket error!\n");  
            return 2;  
        }  
  
    struct sockaddr_in server;  
    server.sin_family = AF_INET;  
    server.sin_port = htons(atoi(argv[2]));  
    server.sin_addr.s_addr = inet_addr(argv[1]);  
  
    if(connect(sock,(struct sockaddr*)&server,sizeof(server)) < 0){  
            printf("connect error!\n");  
            return 3;  
        }  
  
    char buf[MAX];  
    while(1){  
            printf("please Enter# ");  
            fflush(stdout);  
            read(0,buf,sizeof(buf)-1);  
            /*if(s > 0){  
                    buf[s-1] = 0;  
                    if(strcmp("quit",buf) == 0){  
                                printf("client quit!\n");  
                                break;  
                            }*/  
            ssize_t write_size = write(sock,buf,strlen(buf));
            if(write_size < 0){
                perror("write");
                continue;
            }
            ssize_t s = read(sock,buf,sizeof(buf)-1);
            if(s < 0){
                perror("read");
                continue;
            }
            if(s == 0){
                printf("server close!\n");
                break;
            }
            //buf[s] = 0;  
            printf("server Echo# %s\n",buf); 
    }  
    close(sock);  
    return 0;  
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值