首页 > 代码库 > linux编程---网络编程之复用I/O模型

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
 
 

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