第6章 I/O复用:select和poll函数

来源:互联网 发布:2017fc2破解版域名设置 编辑:程序博客网 时间:2024/05/02 02:34

I/O复用:一种预先告知内核的能力,使得内核一旦发现进程指定的一个或多个I/O条件就绪,它就通知进程。


同步I/O:导致请求的进程阻塞,直到I/O操作完成。

异步I/O:不导致请求进程阻塞。


I/O复用模型(select、poll):


5种I/O模型比较:

/* According to POSIX.1-2001, POSIX.1-2008 */#include <sys/select.h>    /* According to earlier standards */       #include <sys/time.h>       #include <sys/types.h>       #include <unistd.h>int select(int nfds, fd_set *readfds, fd_set *writefds,                  fd_set *exceptfds, struct timeval *timeout);void FD_CLR(int fd, fd_set *set);int  FD_ISSET(int fd, fd_set *set);void FD_SET(int fd, fd_set *set);void FD_ZERO(fd_set *set);#include <sys/select.h>int pselect(int nfds, fd_set *readfds, fd_set *writefds,fd_set *exceptfds, const struct timespec *timeout,const sigset_t *sigmask);/*  Feature Test Macro Requirements for glibc (see feature_test_macros(7)):pselect(): _POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 600*/


select客户端:

#include "../Gnet.h"void do_client(int connfd){    char buf[MAX_LINE];    int maxfd;    fd_set rset;    int n;    int closewr;    closewr = 0;    while(1)    {        FD_ZERO(&rset);        if(closewr == 0)            FD_SET(STDIN_FILENO, &rset);        FD_SET(connfd, &rset);        maxfd = STDIN_FILENO > connfd ? STDIN_FILENO : connfd;        if(select(maxfd+1, &rset, NULL, NULL, NULL) < 0)            perr_exit("select error.");        if(FD_ISSET(connfd, &rset))        {            if((n = Read(connfd, buf, MAX_LINE)) == 0)            {                if(closewr == 1)                    return;                else                    perr_exit("server terminated.");            }            Write(STDOUT_FILENO, buf, n);        }        if(FD_ISSET(STDIN_FILENO, &rset))        {            if((n = Read(STDIN_FILENO, buf, MAX_LINE)) == 0)            {                shutdown(connfd, SHUT_WR);                FD_CLR(STDIN_FILENO, &rset);                closewr = 1;            }            else                Write(connfd, buf, n);        }    }}int main(int argc, const char* argv[]){    int connfd;    struct sockaddr_in server_addr;    if(argc < 2)        perr_exit("usage : client <IPaddress>");    connfd = Socket(AF_INET, SOCK_STREAM, 0);    memset(&server_addr, 0, sizeof(server_addr));    server_addr.sin_family = AF_INET;    server_addr.sin_port = htons(SERVER_PORT);    inet_pton(AF_INET, argv[1], &server_addr.sin_addr);    Connect(connfd, (struct sockaddr*)&server_addr, sizeof(server_addr));    do_client(connfd);    return 0;}

select服务器:

#include "../Gnet.h"int main(int argc, const char* argv[]){    int lfd, connfd;    int maxfd;    int client[FD_SETSIZE], maxi, findi;    int nready;    int nread;    struct sockaddr_in server_addr, client_addr;    socklen_t client_addr_len;    fd_set allset, rset;    char buf[MAX_LINE];    memset(&server_addr, 0, sizeof(server_addr));    server_addr.sin_family = AF_INET;    server_addr.sin_addr.s_addr = htonl(INADDR_ANY);    server_addr.sin_port = htons(SERVER_PORT);    lfd = Socket(AF_INET, SOCK_STREAM, 0);    Bind(lfd, (const struct sockaddr*)&server_addr, sizeof(server_addr));    Listen(lfd, LISTENQ);    maxfd = lfd;    maxi = -1;    for(int i=0; i<FD_SETSIZE; ++i)        client[i] = -1;    FD_ZERO(&allset);    FD_SET(lfd, &allset);    printf("waiting for connecting.\n");    while(1)    {        rset = allset;        nready = select(maxfd+1, &rset, NULL, NULL, NULL);        if(nready < 0)            perr_exit("select error.");        if(FD_ISSET(lfd, &rset))        {            client_addr_len = sizeof(client_addr);            connfd = Accept(lfd, (struct sockaddr*)&client_addr, &client_addr_len);            for(findi = 0; findi < FD_SETSIZE; ++findi)            {                if(client[findi] < 0)                {                    client[findi] = connfd;                    break;                }            }            if(findi == FD_SETSIZE)                Close(connfd);            else            {                FD_SET(connfd, &allset);                if(connfd > maxfd)                    maxfd = connfd;                if(findi > maxi)                    maxi = findi;                if(--nready <= 0)                    continue;            }        }        for(int i=0; i <= maxi; ++i)        {                    if(client[i] < 0)                continue;            if(FD_ISSET(client[i], &rset))            {                if((nread = Read(client[i], buf, MAX_LINE)) == 0)                {                    Close(client[i]);                    FD_CLR(client[i], &allset);                    client[i] = -1;                }                else                    Write(client[i], buf, nread);                if(--nready <= 0)                    break;            }        }    }    return 0;}


    #include <poll.h>    int poll(struct pollfd *fds, nfds_t nfds, int timeout);    #define _GNU_SOURCE         /* See feature_test_macros(7) */    #include <signal.h>    #include <poll.h>    int ppoll(struct pollfd *fds, nfds_t nfds,            const struct timespec *tmo_p, const sigset_t *sigmask);


poll服务器:

#include "../Gnet.h"int main(int argc, const char* argv[]){    int lfd, connfd;    int maxi, findi;    int nready;    int nread;    struct sockaddr_in server_addr, client_addr;    socklen_t client_addr_len;        char buf[MAX_LINE];    struct pollfd client[OPEN_MAX];    memset(&server_addr, 0, sizeof(server_addr));    server_addr.sin_family = AF_INET;    server_addr.sin_addr.s_addr = htonl(INADDR_ANY);    server_addr.sin_port = htons(SERVER_PORT);    lfd = Socket(AF_INET, SOCK_STREAM, 0);    Bind(lfd, (const struct sockaddr*)&server_addr, sizeof(server_addr));    Listen(lfd, LISTENQ);    client[0].fd = lfd;    client[0].events = POLLRDNORM;    for(int i=1; i<OPEN_MAX; ++i)        client[i].fd = -1;    maxi = 0;    printf("waiting for connecting.\n");    while(1)    {        nready = poll(client, maxi+1, -1);        if(nready < 0)            perr_exit("poll error.");        if(client[0].revents & POLLRDNORM)        {            client_addr_len = sizeof(client_addr);            connfd = Accept(lfd, (struct sockaddr*)&client_addr, &client_addr_len);            for(findi=1; findi<OPEN_MAX; ++findi)            {                if(client[findi].fd < 0)                {                    client[findi].fd = connfd;                    break;                }            }            if(findi == OPEN_MAX)                Close(connfd);            else            {                if(findi > maxi)                    maxi = findi;                client[findi].events = POLLRDNORM;                if(--nready <= 0)                    continue;            }        }        for(int i =1; i <= maxi; ++i)        {            if(client[i].fd < 0)                continue;            if(client[i].revents & (POLLRDNORM | POLLERR))            {                if((nread = Read(client[i].fd, buf, MAX_LINE)) < 0)                {                    client[i].fd = -1;                    printf("read error.");                }                else if(nread == 0)                {                    Close(client[i].fd);                    client[i].fd = -1;                }                else                    Write(client[i].fd, buf, nread);                if(--nready <= 0)                    break;            }        }    }    return 0;}

github:https://github.com/gongluck/CodeBase/tree/master/notes/unpv13-notes

原创粉丝点击