linux编程---网络编程之复用I/O模型

模型一:阻塞模型---进程效率低;CPU利用低

模型二:非阻塞模型---进程效率高;但是CPU利用率低;

模型三:复用I/O模型---CPU利用率提高

思想:对于任何一个套接字描述符发生事件时才由系统去唤醒进程,从而不需要因轮询而占用CPU;

对于I/O复用典型的应用如下:

(1)当客户处理多个描述字时(一般是交互式输入和网络套接口),必须使用I/O复用。

(2)当一个客户同时处理多个套接口时,而这种情况是可能的,但很少出现。

(3)如果一个TCP服务器既要处理监听套接口,又要处理已连接套接口,一般也要用到I/O复用。

(4)如果一个服务器即要处理TCP,又要处理UDP,一般要使用I/O复用。

(5)如果一个服务器要处理多个服务或多个协议,一般要使用I/O复用。

函数:select

int select(int nfds, fd_set *readset, fd_set *writeset, fd_set *exceptset, struct timeval *timeout);
函数是用来对文件描述符集监视的;只要集合中有文件描述符发生事件了,表示就绪了;
fd_set *readset, fd_set *writeset, fd_set *exceptset表示该函数监视的事件类型;
struct timeval *timeout表示来看事件发生前如何操作,是一直等待(NULL),不等待直接返回(0);还是等待一定时间后返回(大于0的值)
int nfds表示用来设置select检查文件描述符的最大值;故而他检测的值范围是0~nfds-1。
返回值就是发生事件的个数,如果没有返回0;如果错误则返回-1;

一个进程启动时,都会打开3个文件:标准输入、标准输出和标准出错处理。这3个文件分别对应文件描述符为0、1和2(宏替换STDIN_FILENO、STDOUT_FILENO和STDERR_FILENO)
 
效果:此函数让对事件发生过程交给了内核去处理;不像前面阻塞模式中,对于每个套接字描述符都得去等待而降低进程效率;也不像非阻塞中,对于每个套接字描述符都得不断轮询扫描而达到是否有事件发生,而降低CPU利用率。本函数将多个合一的效果,多个套接字事件发生效果,集中到一个套接字集合中,只要有则就可以焕发进程处理。
 
实例:
#include "server.h"

int main()
{
    int listen_fd, connect_fd, max_fd;
    struct sockaddr_in serveraddr, clientaddr;
    char buf[MAXBUF];
    int length;
    fd_set rdfs, tempfs;
    int num;


    listen_fd = socket(AF_INET, SOCK_STREAM, 0);

    memset(&serveraddr, 0, sizeof(serveraddr));
    serveraddr.sin_family = AF_INET;
    serveraddr.sin_port = htons(8000);
    serveraddr.sin_addr.s_addr = inet_addr("192.168.0.104");

    bind(listen_fd, (SA *)&serveraddr, sizeof(serveraddr));
    listen(listen_fd, 10);
    //connect_fd = bind();
    
    memset(buf, '\0', sizeof(buf));
    FD_ZERO(&rdfs);
    FD_SET(0, &rdfs);
    FD_SET(listen_fd, &rdfs);
    max_fd = listen_fd;
    
    int i;

    while(1)
    {
        tempfs = rdfs;
        printf("selecting...\n");

        if((num = select(max_fd + 1, &tempfs, NULL, NULL, NULL))== -1)
        {
            perror("select failed!\n");
            exit(-1);
        }
        else if(num > 0)
        {
            printf("the current fd stream number is : %d\n" , num);
        }

        printf("select success...\n");
    //    sleep(1);
        
        for(i=0; i< max_fd + 1; i++)
        {
            if(FD_ISSET(i, &tempfs))
            {
                if(i == STDIN_FILENO)
                {
                    fgets(buf, sizeof(buf), stdin);
                    printf("input :%s",buf);
                }

                if(i == listen_fd)
                {
                    length = sizeof(clientaddr);
                    printf("connecting...");
                    connect_fd = accept(listen_fd, (SA *)&clientaddr, &length);
                    printf("connected!\n");
                    FD_SET(connect_fd, &rdfs);

                    if(max_fd < connect_fd)
                    {
                        max_fd = connect_fd;
                    }

                    printf("IP: %s port: %d\n", inet_ntoa(clientaddr.sin_addr),ntohs(clientaddr.sin_port));
                }
                else
                {
                    memset(buf, 0, sizeof(buf));
                    read(i, buf, sizeof(buf));
                    printf("Get Message:%s\n", buf);
                    close(i);
                    FD_CLR(i, &rdfs);

                    if(max_fd == i)
                    {
                        max_fd --;
                    }
                }

            }
        }
    }

    return 0;
}
程序来源:http://blog.chinaunix.net/uid-26773174-id-3181442.html
 
 
posted @ 2014-09-11 10:34  miner007  阅读(266)  评论(0编辑  收藏  举报