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