Unix系統編程(7) - I/O多路複用之poll

poll的機制與select類似,與select在本質上沒有多大差別,管理多個描述符也是進行輪詢,根據描述符的狀態進行處理,但是poll沒有最大文件描述符數量的限制
poll和select同樣存在一個缺點就是,包含大量文件描述符的數組被整體複製於用戶態和內核的地址空間之間,而不論這些文件描述符是否就緒,它的開銷隨着文件描述符數量的增加而線性增大。

服務端代碼下載

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

#define SERV_PORT 8000
#define MAXLINE 1024
#define OPEN_MAX 1024


int main()
{
    int listenfd, connfd;
    struct sockaddr_in server_addr, client_addr;    
    struct pollfd client[OPEN_MAX];
    int i = 0, maxi, nready, clientlen, sockfd, n;
    char buf[MAXLINE];

    listenfd = socket(AF_INET, SOCK_STREAM, 0);

    bzero(&server_addr, sizeof(server_addr));    
    server_addr.sin_port = htons(SERV_PORT);
    server_addr.sin_family = AF_INET;
    server_addr.sin_addr.s_addr = htonl(INADDR_ANY);

    bind(listenfd, (struct sockaddr *)&server_addr, sizeof(server_addr));

    listen(listenfd, 20);

    client[0].fd = listenfd;
    client[0].events = POLLRDNORM;
    for(i = 1; i < OPEN_MAX; ++i)
        client[i].fd  = -1;
    maxi = 0;

    for(;;)
    {
        nready = poll(client, maxi + 1, -1);
        if(client[0].revents & POLLRDNORM)              //新的客戶端鏈接請求
        {
            clientlen = sizeof(client_addr);
            connfd = accept(listenfd, (struct sockaddr*)&client_addr, &clientlen);
            for(i=1; i<OPEN_MAX; ++i)
            {
                if(client[i].fd < 0)
                {
                    client[i].fd = connfd;
                    break;
                }
            }
            if(i == OPEN_MAX)
                printf("too many clients! \n ");
            client[i].events = POLLRDNORM;
            if(i > maxi)
                maxi = i;
            if(--nready <= 0)
                continue;
        }

        for(i=0; i<=maxi; ++i)
        {
            if((sockfd = client[i].fd) < 0)
                continue;
            if(client[i].revents & (POLLRDNORM | POLLERR))
            {
                if((n=read(client[i].fd, buf, sizeof(buf))) <= 0)
                {
                    close(client[i].fd);
                    client[i].fd = -1;
                }
                else
                    write(client[i].fd, buf, n);

                if(--nready <= 0)
                    break;
            }
        }
    }
    return 0;
}
發佈了110 篇原創文章 · 獲贊 125 · 訪問量 34萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章