真实的国产乱ⅩXXX66竹夫人,五月香六月婷婷激情综合,亚洲日本VA一区二区三区,亚洲精品一区二区三区麻豆

成都創(chuàng)新互聯網站制作重慶分公司

I/O多路復用-創(chuàng)新互聯

I/O模型

在UNIX/Linux下主要有4種I/O 模型:
阻塞I/O:最常用
非阻塞I/O:可防止進程阻塞在I/O操作上,需要輪詢
I/O 多路復用:允許同時對多個I/O進行控制
信號驅動I/O:一種異步通信模型
阻塞I/O
阻塞I/O 模式是最普遍使用的I/O 模式,大部分程序使用的都是阻塞模式的I/O 。
缺省情況下,套接字建立后所處于的模式就是阻塞I/O 模式。
很多讀寫函數在調用過程中會發(fā)生阻塞。
讀操作中的read、recv、recvfrom
寫操作中的write、send
其他操作:accept、connect
非阻塞I/O
當我們將一個套接字設置為非阻塞模式,我們相當于告訴了系統(tǒng)內核:“當我請求的I/O 操作不能夠馬上完成,你想讓我的進程進行休眠等待的時候,不要這么做,請馬上返回一個錯誤給我?!?br />當一個應用程序使用了非阻塞模式的套接字,它需要使用一個循環(huán)來不停地測試是否一個文件描述符有數據可讀(稱做polling)。
應用程序不停的polling 內核來檢查是否I/O操作已經就緒。這將是一個極浪費CPU 資源的操作。
這種模式使用中不普遍。
非阻塞I/O實現:
fcntl()函數
當你一開始建立一個套接字描述符的時候,系統(tǒng)內核將其設置為阻塞IO模式。
可以使用函數fcntl()設置一個套接字的標志為O_NONBLOCK 來實現非阻塞。
代碼實現;
1.fcntl( )函數int fcntl(int fd, int cmd, long arg);
int flag;
flag = fcntl(sockfd, F_GETFL, 0);
flag |= O_NONBLOCK;
fcntl(sockfd, F_SETFL, flag);
2.ioctl() 函數
int b_on =1;
ioctl(sock_fd, FIONBIO, &b_on);
多路復用I/O
應用程序中同時處理多路輸入輸出流,若采用阻塞模式,將得不到預期的目的;
若采用非阻塞模式,對多個輸入進行輪詢,但又太浪費CPU時間;
若設置多個進程,分別處理一條數據通路,將新產生進程間的同步與通信問題,使程序變得更加復雜;
比較好的方法是使用I/O多路復用。其基本思想是:
先構造一張有關描述符的表,然后調用一個函數。當這些文件描述符中的一個或多個已準備好進行I/O時函數才返回。
函數返回時告訴進程那個描述符已就緒,可以進行I/O操作。

沙縣網站建設公司創(chuàng)新互聯,沙縣網站設計制作,有大型網站制作公司豐富經驗。已為沙縣上千家提供企業(yè)網站建設服務。企業(yè)網站搭建\成都外貿網站建設要多少錢,請找那個售后服務好的沙縣做網站的公司定做!select()實現多路復用

int select(int n, fd_set *read_fds, fd_set *write_fds, fd_set *except_fds, struct timeval *timeout);
select()參數
maxfd
所有監(jiān)控的文件描述符中大的那一個加1
read_fds
所有要讀的文件文件描述符的集合
write_fds
所有要的寫文件文件描述符的集合
except_fds
其他要向我們通知的文件描述符 (異常集合)
timeout
超時設置.
Null:一直阻塞,直到有文件描述符就緒或出錯
時間值為0:僅僅檢測文件描述符集的狀態(tài),然后立即返回
時間值不為0:在指定時間內,如果沒有事件發(fā)生,則超時返回

宏的形式:
void FD_ZERO(fd_set *fdset) //集合清零
void FD_SET(int fd,fd_set *fdset) //把fd加入集合
void FD_CLR(int fd,fd_set *fdset) //把fd刪除
int FD_ISSET(int fd,fd_set *fdset) //判斷fd是否在集合中。
在這里插入圖片描述
select使用步驟:
首先,建立相關讀集合、寫集合或異常集合,集合清零。
其次,把關心的集合加入到相關集合中,并更新maxfd
接著,調用select去監(jiān)控集合中的狀態(tài),當有數據時,退出select阻塞。
然后,依次判斷那個文件描述符是否有效,然后處理,若是客戶退出,就用FD_CLR清掉FD,并更新maxfd
如果,accept了一個新描述符,就加入到集合中,并更新maxfd。
最后,回到開始,繼續(xù)循環(huán)。

練習:
基于tcp模型的IO多路復用(select)程序,在服務器端采用select來實現客戶端的多路并發(fā)
代碼如下:
客戶端代碼:

#ifndef __MAKEU_NET_H__
#define __MAKEU_NET_H__
#include#include#include#include#include#include#include#include#include#define SERV_PORT 5001
#define SERV_IP_ADDR "192.168.203.130"
#define BACKLOG 5
#define QUIT_STR "quit"
#include#define SERV_RESP_STR "Server:"
#include#endif
void usage(char *s){printf("\n%s serv_ip serv_port\n",s);
	printf("\n\t serv_ip:server ip address");
	printf("\n\t serv_port:server port(>5000)\n\n");
}

int main(int argc, char *argv[])
{int fd = -1;
	int port;
	if(argc != 3){usage(argv[0]);
		exit(1);
	}
	struct sockaddr_in sin;
	//1.創(chuàng)建socket fd
	if((fd = socket(AF_INET,SOCK_STREAM,0))< 0){perror("socket");
		exit(1);
	}
	port = atoi(argv[2]);
	if(port< 5000){usage(argv[0]);
		exit(1);

	}
	//2.連接服務器
	bzero(&sin,sizeof(sin));
	sin.sin_family = AF_INET;
	sin.sin_port = htons(port);  //網絡字節(jié)序端口號
	if(inet_pton(AF_INET,argv[1],(void *)&sin.sin_addr)!=1){perror("inet_pton");
		exit(1);
	}
	if(connect(fd,(struct sockaddr *)&sin,sizeof(sin))< 0){perror("connect");
		exit(1);
	}


	fd_set rset;
	int maxfd = -1;
	int ret = -1;
	struct timeval tout;
	char buf[BUFSIZ];
	while(1){FD_ZERO(&rset);
		FD_SET(0,&rset);
		FD_SET(fd,&rset);
		maxfd = fd;
		
		tout.tv_sec = 5;
		tout.tv_usec = 0;

		select(maxfd+1,&rset,NULL,NULL,&tout);
		if(FD_ISSET(0,&rset)){//標準鍵盤上有輸入
			//讀取鍵盤輸入
			bzero(buf,BUFSIZ);
			do{		ret = read(0,(void *)buf,BUFSIZ-1);
			}while((ret< 0) && (EINTR == errno));
			if(ret< 0){		perror("read");
				continue;
			}
			if(ret == 0){		continue;
			}
			if(write(fd,buf,strlen(buf))< 0){		perror("write () to socket");
				continue;
			}
			if(!strncasecmp(buf,QUIT_STR,strlen(QUIT_STR))){		printf("client is exiting!\n");
				break;
			}
		}	
		if(FD_ISSET(fd,&rset)){//服務器給發(fā)過來數據
			//讀取套接字數據	
			bzero(buf,BUFSIZ);
			do{		ret = read(fd,(void *)buf,BUFSIZ-1);
			}while((ret< 0) && (EINTR == errno));
			if(ret< 0){		perror("read from socket");
				continue;
			}
			if(ret == 0){//服務器關閉
				break;
			}
			printf("server said:%s\n",buf);
			//there is a bug FIXME
			if((strlen(buf) >strlen(SERV_RESP_STR))
					&& (!strncasecmp(buf+strlen(SERV_RESP_STR),QUIT_STR,strlen(QUIT_STR)))){		printf("server client is exiting!\n");
				break;
			}
		}

	}
	close(fd);
	return 0;
}

服務器代碼:

#ifndef __MAKEU_NET_H__
#define __MAKEU_NET_H__
#include#include#include#include#include#include#include#include#include#define SERV_PORT 5001
#define SERV_IP_ADDR "192.168.203.130"
#define BACKLOG 5
#define QUIT_STR "quit"
#include#define SERV_RESP_STR "Server:"

#include#endif
#include "net.h"
void * cli_data_handle(void * arg);
int creatFd();
int main(int argc, char *argv[])
{fd_set rset,clientfds;
	int maxfd = -1;
	int i;
	int fd,newfd;
	char buf[BUFSIZ];
	struct timeval tout;
	int ret = 0;

	fd = creatFd();

	maxfd = fd+1;

	FD_ZERO(&clientfds);

	while(1){FD_ZERO(&rset);
		FD_SET(fd,&rset);

		i = fd;
		while(++i< maxfd){	if(FD_ISSET(i,&clientfds)){		FD_SET(i,&rset);
			}
		}
		tout.tv_sec = 5;
		tout.tv_usec = 0;

		ret = select(maxfd,&rset,NULL,NULL,&tout);
		i = fd;
		while(++i< maxfd){	if(FD_ISSET(i,&rset)){		bzero(buf,BUFSIZ);
				read(i,buf,BUFSIZ);
				printf("buf=%s\n",buf);
				if(!strncasecmp(buf,"quit",4)){close(i);
					FD_CLR(i,&clientfds);
					printf("\tclientfd %d exit\n",i);
				}
			}
		}
		if(FD_ISSET(fd,&rset)){	struct sockaddr_in cin;
			socklen_t addrlen = sizeof(cin);	
			if((newfd = accept(fd,(struct sockaddr *)&cin,&addrlen))< 0){perror("accept");exit(1);}
			FD_SET(newfd,&clientfds);
			maxfd = (maxfd >newfd) ? maxfd : newfd+1;
		}

	}

	return 0;

}
int creatFd(){//封裝,fd(由socket創(chuàng)建,并由bind綁定,listen傾聽的fd)
	int fd = socket(AF_INET,SOCK_STREAM,0);
	if(fd< 0){perror("socket");exit(1);}
	struct sockaddr_in sin;
	socklen_t addrlen = sizeof(sin);
	memset(&sin,0,sizeof(sin));
	sin.sin_family = AF_INET;
	sin.sin_port = htons(SERV_PORT);
	sin.sin_addr.s_addr = htonl(INADDR_ANY);
	if(bind(fd,(struct sockaddr *)&sin,addrlen)< 0){perror("bind");exit(1);}
	if(listen(fd,BACKLOG)< 0){perror("listen");exit(1);}
	return fd;
}

你是否還在尋找穩(wěn)定的海外服務器提供商?創(chuàng)新互聯www.cdcxhl.cn海外機房具備T級流量清洗系統(tǒng)配攻擊溯源,準確流量調度確保服務器高可用性,企業(yè)級服務器適合批量采購,新人活動首月15元起,快前往官網查看詳情吧


當前文章:I/O多路復用-創(chuàng)新互聯
文章路徑:http://weahome.cn/article/dsspgd.html

其他資訊

在線咨詢

微信咨詢

電話咨詢

028-86922220(工作日)

18980820575(7×24)

提交需求

返回頂部