Linux I/O复用——poll()

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Linux I/O复用——poll()相关的知识,希望对你有一定的参考价值。

1、poll()

  poll()系统调用和select()类似,也是轮询一定数量的文件描述符,以测试其是否有就绪者。

  API函数:

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

  参数:nfds+1;

  struct pollfd {
    int   fd;         /* file descriptor */
    short events;     /* requested events */
    short revents;    /* returned events */
  };

  其中,fd成员是指定的文件描述符,events成员告诉poll监听哪些事件,revents是由内核修改。

  有一些宏作为辅助事件参数;

2、代码实现

(1)、utili.h

#include<unistd.h>
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<sys/socket.h>
#include<arpa/inet.h>
#include<netinet/in.h>
#include<assert.h>

#include<sys/select.h>

#define SERVER_IP "127.0.0.1"
#define SERVER_PORT  8787
#define LISTEN_QUEUE 5
#define SIZE 10
#define BUFFER_SIZE 256

#include<poll.h>
#define OPEN_MAX 1000

(2)、ser.c

#include"../utili.h"


static int socket_bind(const char *ip, int port){
    int listenfd = socket(AF_INET, SOCK_STREAM, 0);
    struct sockaddr_in addrSer;
    addrSer.sin_family = AF_INET;
    //addrSer.sin_addr.s_addr = inet_addr(ip);
    inet_pton(AF_INET, ip, &addrSer.sin_addr);
    addrSer.sin_port = htons(port);
    bind(listenfd, (struct sockaddr*)&addrSer, sizeof(struct sockaddr));
    return listenfd;
}

static void handle_connection(struct pollfd *connfds, int num){
    char buffer[BUFFER_SIZE];
    int i;
    for(i=1; i<=num; ++i){
        if(connfds[i].fd == -1) 
            continue;
        if(connfds[i].revents & POLLIN){
            recv(connfds[i].fd, buffer, BUFFER_SIZE, 0); 
            printf("Server accept client msg:>%s\n",buffer);
            send(connfds[i].fd, buffer, strlen(buffer)+1, 0); 
        }   
    }   
}
static void do_poll(int listenfd){
    struct sockaddr_in addrCli;
    int connfd;
    struct pollfd clientfds[OPEN_MAX];
    clientfds[0].fd = listenfd;
    clientfds[0].events = POLLIN;
    int i;
    for(i=1; i<OPEN_MAX; ++i){
        clientfds[i].fd = -1;
    }

    int nready;
    int max = 0;
    for(;;){
        nready = poll(clientfds, max+1, -1);
        if(nready == -1){
            perror("poll");
            return;
        }
        if(nready == 0){
            printf("Server Wait Time Out.\n");
            continue;
        }
        if(clientfds[0].revents & POLLIN){
            socklen_t len = sizeof(struct sockaddr);
            connfd = accept(listenfd, (struct sockaddr*)&addrCli, &len);
            int i;
            for(i=1; i<OPEN_MAX; ++i){
                if(clientfds[i].fd == -1){
                    clientfds[i].fd = connfd;
                    break;
                }
            }

            if(i == OPEN_MAX){
                printf("Over Load.\n");
                exit(1);
            }

            clientfds[i].events = POLLIN;
            max = (i>max ? i : max);
        }

        handle_connection(clientfds, max);
    }
}
int main(void){
    int listenfd;
    listenfd = socket_bind(SERVER_IP, SERVER_PORT);
    listen(listenfd, LISTEN_QUEUE);
    do_poll(listenfd);
    return 0;
}

(3)、cli.c

#include"../utili.h"

static void handle_connection(int sockfd){
    struct pollfd pfds[2];
    pfds[0].fd = sockfd;
    pfds[0].events = POLLIN;
    pfds[1].fd = STDIN_FILENO;
    pfds[1].events = POLLIN;

    char buffer[BUFFER_SIZE];
    for(;;){
        poll(pfds, 2, -1);  //-1表示永不超时
        if(pfds[0].revents & POLLIN){
            recv(sockfd, buffer, BUFFER_SIZE, 0); 
            printf("msg:> %s\n",buffer);
        }   
        if(pfds[1].revents & POLLIN){
            scanf("%s", buffer);
            //read(STDIN_FILENO, buffer, BUFFER_SIZE);
            send(sockfd, buffer, strlen(buffer)+1, 0); 
        }   
    }   
}
int main(void){
    int sockfd = socket(AF_INET, SOCK_STREAM, 0); 
    struct sockaddr_in addrSer;
    addrSer.sin_family = AF_INET;
    addrSer.sin_port = htons(SERVER_PORT);
    addrSer.sin_addr.s_addr = inet_addr(SERVER_IP);
    connect(sockfd, (struct sockaddr*)&addrSer, sizeof(struct sockaddr));

    handle_connection(sockfd);
    return 0;
}

运行结果

服务器端

技术分享

客户端1

技术分享

客户端2

技术分享




本文出自 “11586096” 博客,请务必保留此出处http://11596096.blog.51cto.com/11586096/1856818

以上是关于Linux I/O复用——poll()的主要内容,如果未能解决你的问题,请参考以下文章

Linux网络编程——I/O复用之poll函数

Linux I/O复用中select poll epoll模型的介绍及其优缺点的比較

I/O多路复用

linux下select,poll,epoll的使用与重点分析

I/O多路复用之poll

I/O复用 select和poll