I/O多路复用之poll服务器

上一篇介绍了关于I/O多路复用的select服务器,今天便介绍一下poll服务器。对两种模式再做一个比较。
I/O多路复用select服务器:
http://blog.csdn.net/payshent/article/details/74909010

一、poll函数的介绍
我们先看一下poll函数的原型:
这里写图片描述
我们可以看出poll函数有三个参数,poll系统调用和select的系统调用类似,也是在指定的时间内轮询一定数量的文件描述符,来看其中是否有就绪。
1、fds:fds是pollfd结构类型的数组,指定我们所有感兴趣的文件描述符上的可读、可写、异常事件。
poll结构体的定义如下:
这里写图片描述
在这里,fd是指定的文件描述符,events成员告诉poll监听的fd上的哪些事件,是一系列事件的按位或。revents是由内核修改的,通知应用程序fd上实际发生了哪些事件,poll支持的类型事件如下所示:
这里写图片描述
这里写图片描述
上面虽然列出了所有的poll事件类型,但是我们最为常用的还是POLLIN(普通或优先数据可读)、POLLOUT(普通或优先数据可写)、POLLERR(错误)、POLLHUP(挂起)
2、nfds:指定被监听的事件集合fds的大小,其中nfds_t的定义如下:

typedef unsigned long int nfds_t;

3、timeout:
指定poll的超时值,单位是毫秒。timeout是-1,poll将永远阻塞,知道某个事件发生;timeout为0的时候,poll调用立即返回
4、返回值
poll的返回值情况和select的返回值情况是一致的,有问题请看select服务器。

二、select和poll的优缺点分析
这里写图片描述
select的缺点:
1、每次调用select,都需要把fd的集合从用户态拷贝到内核态,这个开销在fd很大的时会很大
2、同时每次调用select都需要在内核遍历传递进来的所有fd,这个开销在fd很多时也很大
3、select支持的文件描述符太小了,默认是1024。

三、poll服务器的代码展示

服务器端poll.c:

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

#define BUF_SIZE 1024

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



int startup(const char* ip,int port)
{
    int sock = socket(AF_INET,SOCK_STREAM,0);
    if(sock < 0)
    {
        perror("socket");
        exit(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");
        exit(3);
    }

    if(listen(sock,10) < 0)
    {
        perror("listen");
        exit(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 evs[BUF_SIZE];
    int timeout = 5000;
    int i = 0;
    for(;i < BUF_SIZE;i++)
    {
        evs[i].fd = -1;
        evs[i].events = 0;
    }
    evs[0].fd = listen_sock;
    evs[0].events = POLLIN;
    evs[0].revents = 0;

    int count = 0;

    while(1)
    {
        switch(poll(evs,count+1,timeout))
        {
            case -1:
                {
                    perror("poll");
                    break;
                }
            case 0:
                {
                    printf("time out...\n");
                    break;
                }
            default:
                {
                    for(i = 0;i < BUF_SIZE;i++)
                    {
                        if(evs[i].fd == -1)
                        {
                            continue;
                        }
                        //listen_sock的读事件就绪
                        else if(evs[i].fd == listen_sock && evs[i].revents & POLLIN)
                        {
                            struct sockaddr_in client;
                            socklen_t len = sizeof(client);
                            int new_sock = accept(listen_sock,(struct sockaddr*)&client,&len);
                            if(new_sock < 0)
                            {
                                perror("accept");
                                continue;
                            }
                            printf("get a new client! ip:%s port:%d\n",inet_ntoa(client.sin_addr),ntohs(client.sin_port));
                            int j = 1;
                            for(; j < BUF_SIZE;j++)
                            {
                                if(evs[j].fd == -1)
                                {

                                    evs[j].fd = new_sock;
                                    evs[j].events = POLLIN;
                                    break;
                                }
                            }
                            if(j > count)
                            {
                                count = j;
                            }
                            if(j == BUF_SIZE)
                            {
                                close(new_sock);
                            }
                        }
                        //普通事件的读事件就绪
                        else if(evs[i].revents & POLLIN)
                        {
                            char buf[1024];
                            ssize_t s = read(evs[i].fd,buf,sizeof(buf)-1);
                            if(s > 0)
                            {
                                buf[s] = 0;

                                printf("client echo#: %s\n",buf);
                                write(evs[i].fd,buf,strlen(buf));
                                evs[i].revents = 0;
                            }
                            else if(s == 0)
                            {
                                printf("client is cose!!!\n");
                                close(evs[i].fd);
                                evs[i].fd = -1;
                            }
                            else
                            {
                                perror("read");
                                close(evs[i].fd);
                                evs[i].fd = -1;
                            }
                        }
                    }
                    break;
                }
        }
    }
    return 0;
}

客户端:

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

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

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

    int sock = socket(AF_INET,SOCK_STREAM,0);
    if(sock < 0)
    {
        perror("socket");
        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)
    {
        perror("connect");
        return 3;
    }

    //客户端不需要绑定  也不需要监听
    //客户端是先write后read

    char buf[1024];
    while(1)
    {
        printf("please Enter#  ");
        fflush(stdout);
        ssize_t s = read(0,buf,sizeof(buf)-1);
        if(s > 0)
        {
            buf[s-1] = 0;
            write(sock,buf,strlen(buf));
            ssize_t _s = read(sock,buf,sizeof(buf)-1);
            if(_s > 0 )
            {
                buf[_s] = 0;
                printf("server echo# %s\n",buf);
            }
        }
    }


    close(sock);
    return 0;
}

四、代码运行结果
这里写图片描述

这里写图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值