前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >第6章 I/O复用:select和poll函数

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

作者头像
_gongluck
发布2018-03-09 15:29:39
7280
发布2018-03-09 15:29:39
举报

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

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

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

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

5种I/O模型比较:

代码语言:javascript
复制
/* 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客户端:

代码语言:javascript
复制
#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服务器:

代码语言:javascript
复制
#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;
}
代码语言:javascript
复制
    #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服务器:

代码语言:javascript
复制
#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

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2017年11月09日,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档