poll服务器编程综合

一、poll服务器代码

#include<stdio.h>
#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
#include<stdlib.h>
#include<netinet/in.h>
#include<poll.h>
#include<string.h>


static void usage(const char *str)
{
    printf("Usage:%s [serv_ip] [serv_port]\n",str);
}

static int startup(const char *ip,int port)
{
    int sock = socket(AF_INET,SOCK_STREAM,0);
    if(sock < 0)
    {
        perror("socket");
        exit(1);
    }

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

    struct sockaddr_in serv_addr;
    serv_addr.sin_family = AF_INET;
    serv_addr.sin_addr.s_addr = inet_addr(ip);
    serv_addr.sin_port = htons(port);

    int ret  = bind(sock,(struct sockaddr*)&serv_addr,sizeof(serv_addr));
    if(ret < 0)
    {
        perror("bind");
        exit(2);
    }

    ret = listen(sock,128);
    if(ret < 0)
    {
        perror("listen");
        exit(3);
    }
    return sock;
}

//       poll函数第一个参数类型。
//struct pollfd {
//  int   fd;         /* file descriptor */
//  short events;     /* requested events */
//  short revents;    /* returned events */
//};
//

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

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

    struct pollfd peerfd[1024]; //当有就绪事件发生的话会写到这个数组里面。

    peerfd[0].fd = sock;  //首先监听连接套接字。监听它的读事件。
    peerfd[0].events = POLLIN;

    int timeout = -1;  //表示阻塞式等待。
    int i = 1;

    for(; i < 1024; ++i)
    {
        peerfd[i].fd = -1;    //表示这个位置么有被占用。
    }

    while(1)
    {               //int poll(struct pollfd *fds, nfds_t nfds, int timeout); //timeout是一个值传递,不用每次都初始化了。
        int ret = 0;
        switch(ret = poll(peerfd,1024,timeout))
        {
            case 0:
                printf("timeout...\n");
                break;
            case -1:
                perror("poll");
                break;
            default:
                {
                    int i = 0;
                    for(i = 0; i < 1024; ++i)//遍历数组查看有哪些就绪事件发生了。
                    {
                        if(i == 0 && (peerfd[i].revents & POLLIN)  )//有新的连接请求。
                        {
                            struct sockaddr_in client;
                            socklen_t len = sizeof(client);
                            int new_sock = accept(sock,(struct sockaddr*)&client,&len);
                            if(new_sock < 0)
                            {
                                perror("accept");
                                continue;
                            }
                            printf("get a new client\n");
                            int j = 1;
                            for(; j < 1024; ++j)
                            {
                                if(peerfd[j].fd < 0)  //找最小的未被使用的位置。
                                {
                                    peerfd[j].fd = new_sock;
                                    peerfd[j].events = POLLIN;
                                    break;
                                }
                            }

                            if(j == 1024 )
                            {
                                printf("too many client...\n");
                                close(new_sock);
                            }
                        } //if
                        else if(i != 0)
                        {
                            if(peerfd[i].revents & POLLIN) //客户端有读事件发生。
                            {
                                char buf[1024];
                                ssize_t s =  read(peerfd[i].fd,buf,sizeof(buf) - 1);
                                if(s > 0)
                                {
                                    buf[s] = 0;
                                    printf("clinet say:%s\n",buf);
                                    peerfd[i].events = POLLOUT; //读完后监听写事件。
                                }
                                else if(s <= 0)
                                {
                                    close(peerfd[i].fd);
                                    peerfd[i].fd = -1;
                                }
                            }
                            else if(peerfd[i].revents & POLLOUT)//写事件就绪。
                            {
                                /* 客户端写事件发生 */
                                /* 使用浏览器测试,写回到客户端,浏览器会解析字符串,显示 Hellp Epoll! */
                                const char* msg = "HTTP/1.1 200 OK\r\n\r\n<html><br/><h1>Hello poll!</h1></html>";
                                write(peerfd[i].fd, msg, strlen(msg));

                                //写完后关闭套接字。
                                    close(peerfd[i].fd);
                                    peerfd[i].fd = -1;
                            }

                        } //else if

                    } //for

                } //default

        } //switch()
    } //while(1)

    return 0;
}

二、poll服务器优缺点
优点

(1)poll() 不要求开发者计算最大文件描述符加一的大小。 
(2)poll() 在应付大数目的文件描述符的时候相比于select速度更快 
(3)它没有最大连接数的限制,原因是它是基于链表来存储的。

缺点

(1)大量的fd的数组被整体复制于用户态和内核地址空间之间,而不管这样的复制是不是有意义。 
(2)与select一样,poll返回后,需要轮询pollfd来获取就绪的描述符
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值