I/O多路转接-----poll

本文介绍了I/O多路转接技术中的poll机制,作为select的改进版,poll克服了select在文件描述符数量上的限制,提高了在大量fd时的效率。尽管如此,poll仍存在缺点,如在事件发生时需遍历所有fd。文章详细讲解了poll的优点、缺点、基本原型及其参数,并给出了简单的实现概述。
摘要由CSDN通过智能技术生成

在上一篇博客中我们简单的select进行了实现,但是我们都知道select是早期的一个服务器,有缺点,缺点也很明显,它支持的文件描述符只有1024个是比较少的,所以当请求达到一定数量的时候,他就不能被称为高性能服务器了,他就会越来越慢知道挂掉;所以,我们来简单来介绍poll来对select进行改进;

poll的优缺点

优点
  1. poll不需要开发者来计算最大文件描述符+1
  2. poll在应付大数目的文件描述符的时候比select要快
  3. 它没有最大的连接数限制,它是基于链表来存储的
缺点 ####
  1. 大量的fd的数组被整体复制于用户态和内核态之间,而不管这样的复制是否有意义
  2. 与select一样,poll返回后需要轮询pollfd来获取就绪的文件描述符

poll介绍 ###

poll原型
#include<poll.h>
int poll(struct pollfd* fds, nfds_t nfds, int timeout);
第一个参数
struct pollfd
{
    int fd;        //文件描述符
    short events; //注册的事件
    short revents;//实际发生的事件,由内核填充
}
第二个参数

nfds:指定被监听事件集合;

第三个参数

timeout参数指定poll的超时值
-1:poll阻塞式等待
0 :poll调用立即返回

poll简单实现 ###

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

#define NUMBER_MAX_USER 1024

static void usage(const char* proc)
{
    printf("Usage: %s [local_ip] [local_port]\n", proc);
}

int startup(const char* _ip, int _port)
{
    int sock = socket(AF_INET, SOCK_STREAM, 0);
    if(sock < 0)
    {
        perror("socket");
        return 2;
    }

    int opt = 1;
    setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));

    struct sockaddr_in local;
    local.sin_family = AF_INET;
    local.sin_port = htons(_port);
    local.sin_addr.s_addr = inet_addr(_ip);
    if(bind(sock, (struct sockaddr*)&local, sizeof(local)) < 0)
    {
        perror("bind");
        return 3;
    }

    if(listen(sock, 10) < 0)
    {
        perror("listen");
        return 4;
    }
    return sock;
}

int main(int argc, char *argv[])
{
    if(argc != 3)
    {
        usage(argv[0]);
        return 1;
    }

    int listen_sock = startup(argv[1], atoi(argv[2]));

    struct pollfd pofd[NUMBER_MAX_USER];
    int i = 1;
    for(; i < NUMBER_MAX_USER; i++)
    {
        pofd[i].fd = -1;
        pofd[i].events = 0;
    }

    pofd[0].fd = listen_sock;
    pofd[0].events = POLLIN;
    pofd[0].revents = 0;

    while(1)
    {
//      int timeout = 1000;
        int num = poll(pofd, NUMBER_MAX_USER, /*timeout*/-1);
        switch(num)
        {
            case -1:
                {
                    perror("poll");
                }
                break;
            case 0:
                {
                    printf("timeout...\n");
                }
                break;
            default:
                {
                    for(i = 0; i < NUMBER_MAX_USER; i++)
                    {
                        if(pofd[i].fd == -1)
                            continue;
                        else if((pofd[i].fd == listen_sock) && (pofd[i].revents == POLLIN))
                        {
                            struct sockaddr_in client;
                            socklen_t len = sizeof(client);
                            int new_sock = accept(pofd[i].fd, (struct sockaddr*)&client, &len);
                            if(new_sock < 0)
                            {
                                perror("accept");
                                return 5;
                            }
                            printf("get new client... [%s:%d]\n",inet_ntoa(client.sin_addr),ntohs(client.sin_port));
                            int j = 0;
                            for(; j < NUMBER_MAX_USER; j++)
                            {
                                if(pofd[j].fd == -1)
                                    break;
                            }
                            if(j == NUMBER_MAX_USER)
                            {
                                printf("server is full\n");
                                close(new_sock);
                                break;
                            }
                            else
                            {
                                pofd[j].fd = new_sock;
                                pofd[j].events = POLLIN/* | POLLOUT*/;
                            }
                         }//listen_sock only read
                        else if(pofd[i].revents & POLLIN)
                        {
                            char *buf[1024];
                            int ret = read(pofd[i].fd, buf, sizeof(buf)-1);
                            if(ret < 0)
                            {
                                perror("read");
                                return 6;
                            }
                            else if(ret == 0)
                            {
                                printf("time out...");
                                close(pofd[i].fd);
                                pofd[i].fd = -1;
                                continue;
                            }
                            else
                            {
                                buf[ret] = 0;
                                printf("client ###:%s", buf);
                            }
                        }//other read
                        else if(pofd[i].revents & POLLOUT)
                        {
                            const char* msg = "hello world\n";
                            write(pofd[i].fd, msg, strlen(msg));
                            close(pofd[i].fd);
                            pofd[i].fd = -1;
                        }//write

                    }//for
                }//default
                break;
        }//switch
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值