Linux 下 poll模型

poll调用和select调用实现的功能一样,都是网络IO利用的一种机制。poll() 没有像 select() 构建 fd_set 结构体的 3 个数组 ( 针对每个条件分别有一个数组 : 可读性、可写性和错误条件 ) ,然后检查从 0 到 nfds 每个文件描述符。


先看一下poll的调用形式


一,poll调用

[cpp] view plain copy
  1. #include <poll.h>  
  2. int poll(struct pollfd fds[], nfds_t nfds, int timeout);  


二,参数说明

fds:存放需要被检测状态的Socket描述符;与select不同(select函数在调用之后,会清空检测socket描述符的数组),每当调用这个函数之后,系统不会清空这个数组,而是将有状态变化的描述符结构的revents变量状态变化,操作起来比较方便;

nfds:用于标记数组fds中的struct pollfd结构元素的总数量;

timeout:poll函数调用阻塞的时间,单位是MS(毫秒)


struct pollfd结构如下:【在源码文件poll.h文件中】

[cpp] view plain copy
  1. struct pollfd {  
  2.     int fd;          /* poll 的文件描述符.  */
  3.     short events;    /* fd 上感兴趣的事件(等待的事件).*/
  4.     short revents;   /* fd 上实际发生的事件.  */
  5. };  

这个结构中

fd表示文件描述符,

events表示请求检测的事件位掩码

常量 说明
POLLIN 普通或优先级带数据可读
POLLRDNORM 普通数据可读
POLLRDBAND 优先级带数据可读
POLLPRI 高优先级数据可读
POLLOUT 普通数据可写
POLLWRNORM 普通数据可写
POLLWRBAND 优先级带数据可写
POLLERR 发生错误
POLLHUP 发生挂起
POLLNVAL 描述字不是一个打开的文件

 注意:后三个只能作为描述字的返回结果存储在revents中,而不能作为测试条件用于events中。

revents表示检测之后返回的事件位掩码,如果当某个文件描述符有状态变化时,revents的值就不为空。 



三,返回值

  1. 大于0:表示数组fds中有socket描述符的状态发生变化,或可以读取、或可以写入、或出错。并且返回的值表示这些状态有变化的socket描述符的总数量;此时可以对fds数组进行遍历,以寻找那些revents不空的socket描述符,然后判断这个里面有哪些事件以读取数据。
  2. 等于0:表示没有socket描述符有状态变化,并且调用超时。
  3. 小于0:此时表示有错误发生,此时全局变量errno保存错误码。


服务端

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h> /* superset of previous */
#include <sys/time.h>
#include <arpa/inet.h>
#include <poll.h>

#define backlog 5
#define BUFFSIZE 1024

int create_listenfd(const char *ip, unsigned short port)
{
    int listenfd = socket(PF_INET, SOCK_STREAM, 0);
    if(-1 == listenfd)
    {
        perror("socket");
        return -1;
    }
    
    struct sockaddr_in serv_addr;
    memset(&serv_addr, 0, sizeof(serv_addr));
    serv_addr.sin_family = AF_INET;
    serv_addr.sin_port = htons(port);
    serv_addr.sin_addr.s_addr = (ip == NULL ? INADDR_ANY :inet_addr(ip));
    
    if(-1 == bind(listenfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)))
    {
        perror("bind");
        close(listenfd);
        return -1;
    }
    printf("bind success!\n");
    
    if(-1 == listen(listenfd, backlog))
    {
        perror("listen");
        close(listenfd);
        return -1;
    }
    printf("listening ...\n");
    
    return listenfd;
}

int main(int argc, char *argv[])
{
    int listenfd = create_listenfd(NULL,atoi(argv[2]));
    if(-1 == listenfd) 
    {
        return 0;
    }
    
    char buff[BUFFSIZE];
    int recvbytes, sendbytes;
    struct pollfd eventfds[BUFFSIZE];
    memset(eventfds, 0, sizeof(eventfds));

    eventfds[0].fd = STDIN_FILENO;
    eventfds[0].events = POLLIN;
    eventfds[1].fd = listenfd;
    eventfds[1].events = POLLIN;
    
    while(1)
    {    
        int ret = poll(eventfds, BUFFSIZE, 3*1000);
        if(-1 == ret)
        {
            perror("poll");
            break;
        }
        else if(0 == ret)
        {
            printf("timeout...\n");
        }
        else
        {
            for(int i = 0; i <= BUFFSIZE; i++)
            {
                int fd = eventfds[i].fd;
                if(eventfds[i].revents & POLLIN)
                {
                    if(fd == STDIN_FILENO)
                    {
                        fgets(buff, sizeof(buff), stdin);
                        printf("gets:%s",buff);
                    }
                    else if(fd == listenfd)
                    {
                        int connectfd = accept(listenfd, NULL, NULL);
                        if(-1 == connectfd)
                        {
                            perror("accept");
                            close(listenfd);
                            return 0;
                        }
                        printf("A new client(fd=%d) is connect success!\n", connectfd);
                        eventfds[connectfd - listenfd + 1].fd = connectfd;
                        eventfds[connectfd - listenfd + 1].events = POLLIN;
                    }
                    else
                    {
                        recvbytes = recv(fd, buff, sizeof(buff), 0);
                        if(recvbytes < 0)
                        {
                            perror("recv");
                            eventfds[i].events = 0;
                            eventfds[i].fd = -1;
                            close(fd);
                            break;
                        }
                        if(recvbytes == 0)
                        {
                            printf("client(fd=%d) is closed!\n", fd);
                            eventfds[i].events = 0;
                            eventfds[i].fd = -1;
                            close(fd);
                            break;
                        }
                        printf("server recv from client(fd=%d):%s", fd, buff);
                    }
                    
                }
            }
        }
    }
   
    close(listenfd);

    return 0;
}


客户端

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h> /* superset of previous */

#define backlog 5
#define BUFFSIZE 1024

int main(int argc, char *argv[])
{
    int sockfd = socket(PF_INET, SOCK_STREAM, 0);
    if(-1 == sockfd)
    {
        perror("socket");
        exit(EXIT_FAILURE);
    }

    struct sockaddr_in serv_addr;
    memset(&serv_addr, 0, sizeof(serv_addr));
    serv_addr.sin_family = AF_INET;
    serv_addr.sin_port = htons(atoi(argv[2]));
    serv_addr.sin_addr.s_addr = inet_addr(argv[1]);

    if(-1 == connect(sockfd, (struct sockaddr*)&serv_addr, sizeof(serv_addr)))
    {
        perror("connect");
        close(sockfd);
        exit(EXIT_FAILURE);
    }
    printf("connect success!\n");

    char buff[BUFFSIZE];
    int recvbytes, sendbytes;
    while(1)
    {
        fgets(buff, sizeof(buff), stdin);
        if(0 == strncmp(buff, "quit", 4))
        {
            printf("client quit!\n");
            break;
        }
        sendbytes = send(sockfd, buff, strlen(buff)+1, 0);
        if(sendbytes <= 0)
        {
            perror("send");
            break;
        }
    }

    close(sockfd);

    return 0;
}



运行

./server 127.0.0.1 8888
./client 127.0.0.1 8888
./client 127.0.0.1 8888

发布了201 篇原创文章 · 获赞 103 · 访问量 26万+
展开阅读全文

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 大白 设计师: CSDN官方博客

分享到微信朋友圈

×

扫一扫,手机浏览