linux下多路复用模型之Select模型
2015-08-06 11:12
609 查看
Linux关于并发网络分为Apache模型(Process per Connection (进程连接) ) 和TPC , 还有select模型,以及poll模型(一般是Epoll模型)
Select模型极其作用:这文章讲述的很好,没必要重述已有的东西,就直接给链接
http://blog.csdn.net/turkeyzhou/article/details/8609360
我的理解:
对于
该结构用来设定多少时间为超时 ,比如
void FD_CLR(int fd, fd_set *set);
用来清除fd的fd_set ,比如fd为5 ,则表示set集中所有设定等于5的fd_set 都将被清除
int FD_ISSET(int fd, fd_set *set);
判断是否set 与fd是否绑定,如果没有绑定,则返回false,如果绑定了则返回True
将fd值 和set绑定
将set集全部清除
简单的例子:
判断是否有数据输入,有则直接打印出来
View Code
makefile文件:
虽然知道这么多,但是还是觉得Select并没有什么作用。
Select一般是和Socket搭配使用,相当于线程池的效果,但是线程池有缺点,详情看这儿:
/article/2797639.html
/article/1339514.html
关于Select的原理图:
首先来看下一对一的socket的c/s模式
关于socket的一对一的详解
/article/5255432.html
看完这个之后,我们现在可以来看看这个图:
下面为举例:
服务器创建一个socket并bind绑定一个本机地址和设定一个端口,然后进入listen监听状态。采用select模型而非传统apache模型(ppc)或者tpc模型 。 不过Select模型就是有这样一个特点
一般我们default默认的SOMAXCONN为128 当然我们可以另外取一个设定(下面我们设定的是2048)作为最大连接数,虽然可以设置更大,但是缺点是,select模型是一个轮询模式,就是每一个都需要遍历一边所有的链接的fd
查看是否在fd_set集合中,这样,当SOMAXCONN取值非常大时,对于每一个客户端,访问时间都会延迟一点点,这样就是效率不是特别高!
下面是一个简单的多路复用的网络并发Select模型
makefile文件:
客户端:
makefile文件:
效果图:
Select模型极其作用:这文章讲述的很好,没必要重述已有的东西,就直接给链接
http://blog.csdn.net/turkeyzhou/article/details/8609360
我的理解:
/* According to POSIX.1-2001 */ #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);
对于
int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout); 第一个参数 nfds: 第n个文件id的编号 (linux下,一切皆文件) 需要注意的是: nfds = fd+1 (fd 为 FD_SET中的fd) 第二个参数: fd_set *readfds 读取文件编号,如果不需要读取的话 可以设置为NULL 第三 ,四个参数: 同上 第五个参数:为一个定义超时的结构体
struct timeval { time_t tv_sec; /* seconds */ suseconds_t tv_usec; /* microseconds */ };
该结构用来设定多少时间为超时 ,比如
struct timeval ss ; ss.tv_sec =3; ss.tv_usec =0; //表示设定为3秒后为超时,select将会返回0
对于下面这几个函数:
void FD_CLR(int fd, fd_set *set);
用来清除fd的fd_set ,比如fd为5 ,则表示set集中所有设定等于5的fd_set 都将被清除
int FD_ISSET(int fd, fd_set *set);
判断是否set 与fd是否绑定,如果没有绑定,则返回false,如果绑定了则返回True
void FD_SET(int fd, fd_set *set);
将fd值 和set绑定
void FD_ZERO(fd_set *set);
将set集全部清除
简单的例子:
判断是否有数据输入,有则直接打印出来
#include<stdio.h> #include<string.h> #include<sys/select.h> #include<unistd.h> #include<sys/time.h> #include<sys/types.h> #define maxn 6 #define EXIT_FAILURE -1 #define EXIT_SUCCESS 0 int main(int argc , char * argv []){ fd_set mtfd ; int ffd =0; struct timeval outtime ; int retval ; char redbuf[maxn]; FD_ZERO(&mtfd); FD_SET(ffd , &mtfd); // wait up to 5.5 s outtime.tv_sec = 5 ; outtime.tv_usec = 500 ; retval = select(ffd+1 , &mtfd ,NULL , NULL , &outtime); if(-1 == retval ) { printf("error happened ! %d \n" ,__LINE__ ); return EXIT_FAILURE ; } else if(0 == retval ){ printf(" timeout !! %d \n" ,__LINE__ ); return EXIT_FAILURE ; } //means that is good ! printf("retval = %d \n", retval); if( FD_ISSET(ffd , &mtfd) ){ memset(redbuf ,0 , sizeof(redbuf)); printf("reading ... !! "); // read(1 , redbuf ,sizeof(redbuf) ); //use the sys func fread(redbuf , sizeof(redbuf) ,ffd+1 , stdin ); } // fwrite(redbuf ,strlen(redbuf) , 1 , stdout ); // write(1 , redbuf , strlen(redbuf)); printf("buf = %s buf_len = %d \n" , redbuf , strlen(redbuf)); return EXIT_SUCCESS ; }
View Code
makefile文件:
.SUFFIXES: .o.c CC =gcc SRC = Se_keyboard.c OBJ = $(SRC: .c =.o) BIN = Se_keyboard .PHONY: start start: $(OBJ) $(CC) -o $(BIN) $(OBJ) .o.c: $(SRC) $(CC) -g -Wall $@ -c $< .PHONY: clean clean: rm -f $(OBJ)
虽然知道这么多,但是还是觉得Select并没有什么作用。
Select一般是和Socket搭配使用,相当于线程池的效果,但是线程池有缺点,详情看这儿:
/article/2797639.html
/article/1339514.html
关于Select的原理图:
首先来看下一对一的socket的c/s模式
关于socket的一对一的详解
/article/5255432.html
看完这个之后,我们现在可以来看看这个图:
下面为举例:
服务器创建一个socket并bind绑定一个本机地址和设定一个端口,然后进入listen监听状态。采用select模型而非传统apache模型(ppc)或者tpc模型 。 不过Select模型就是有这样一个特点
一般我们default默认的SOMAXCONN为128 当然我们可以另外取一个设定(下面我们设定的是2048)作为最大连接数,虽然可以设置更大,但是缺点是,select模型是一个轮询模式,就是每一个都需要遍历一边所有的链接的fd
查看是否在fd_set集合中,这样,当SOMAXCONN取值非常大时,对于每一个客户端,访问时间都会延迟一点点,这样就是效率不是特别高!
下面是一个简单的多路复用的网络并发Select模型
#include<stdio.h> #include<string.h> #include<stdlib.h> #include<unistd.h> #include<netinet/in.h> #include<netinet/ip.h> #include<sys/socket.h> #include<sys/types.h> #include<sys/time.h> #include<arpa/inet.h> #include<sys/select.h> #include<assert.h> #ifndef EXIT_SUCCESS #define EXIT_SUCCESS 0 #endif #ifndef EXIT_FAILURE #define EXIT_FAILURE -1 #endif #define Max_connect 2048 //usually is SOMAXCONN =128 ,can be change #define maxn 1024 #define Port 5567 #define Ser_addr "192.168.132.128" #define ERROR_EXIT( inf ) \ do{ \ perror( inf ); \ printf("it happened in %d \n", __LINE__); \ exit(-1); \ }while(0); #define Waring( inf ) \ do{ \ perror( inf ); \ printf("it happened in %d \n", __LINE__); \ }while(0); int fds[Max_connect]; int cnt = 1; void print (int fd, const char *str) { assert (str != NULL); printf ("the fd is %d \n", fd); puts (str); } int main (int argv, char *argc[]) { int ser_sfd = -1, i; struct sockaddr_in ser_addr; struct sockaddr_in client_addr; int setfd = 0, optval, maxsockfd; char rebuf[maxn], wbuf[maxn]; // build a socket with ipv4 ans tcp if ((ser_sfd = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) ERROR_EXIT ("socket...!"); // set the type socket /* level ={ SOL_SOCKET ,IPPROTO_TCP} setsockopt is to cancle the jiangsi process */ printf ("ser_sfd = %d \n", ser_sfd); if (setsockopt (ser_sfd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof (optval)) < 0) ERROR_EXIT ("setsockopt...!"); memset (&client_addr, 0, sizeof (client_addr)); memset (&ser_addr, 0, sizeof (ser_addr)); ser_addr.sin_family = AF_INET; ser_addr.sin_port = htons (Port); ser_addr.sin_addr.s_addr = htonl (INADDR_ANY); if (bind (ser_sfd, (struct sockaddr *) &ser_addr, sizeof (ser_addr)) < 0) ERROR_EXIT ("bind..!"); if (listen (ser_sfd, Max_connect) < 0) ERROR_EXIT ("listen...!"); //user the select moduel memset (fds, 0, sizeof (fds)); fd_set fdset, wfd; maxsockfd = ser_sfd; //max socket fd struct timeval tout; tout.tv_sec = 15; tout.tv_usec = 0; while (1) { FD_ZERO (&fdset); //clear //FD_ZERO (&wfd); FD_SET (ser_sfd, &fdset); //bind //FD_SET (ser_sfd, &wfd); struct timeval tout; tout.tv_sec = 15; tout.tv_usec = 0; for (i = 0; i < cnt; i++) { if (fds[i] != 0) FD_SET (fds[i], &fdset); } int tag = select (maxsockfd + 1, &fdset, NULL, NULL, &tout); if (tag == 0) { Waring ("select wait timeout !"); continue; } else if (tag == -1) ERROR_EXIT ("Error select ...!"); //lunxun select for (i = 0; i < cnt; i++) { if (FD_ISSET (fds[i], &fdset)) { int len = recv (fds[i], rebuf, sizeof (rebuf), 0); if (len <= 0) { printf ("%d: \n", fds[i]); close (fds[i]); FD_CLR (fds[i], &fdset); Waring ("client is closed !"); continue; } printf ("the client_ip : %s\n", inet_ntoa (client_addr.sin_addr)); print (fds[i], rebuf); send (fds[i], rebuf, sizeof (rebuf), 0); //hui she memset (rebuf, 0, sizeof (rebuf)); } } //if have a new connect happened // memset(&client_addr , 0 ,sizeof(client_addr)); if (FD_ISSET (ser_sfd, &fdset)) { // memset(&client_addr , 0 ,sizeof(client_addr)); int acplen = sizeof (client_addr); int acp = accept (ser_sfd, (struct sockaddr *) &client_addr, &acplen); printf ("accept return acp=%d \n", acp); if (acp < 0) { Waring ("waring accept acp<=0!"); continue; } //add to arr if (cnt < maxn) fds[cnt++] = acp; else { ERROR_EXIT ("cnt>maxn"); } if (acp > maxsockfd) maxsockfd = acp; } } for (i = 0; i < cnt; i++) { close (fds[i]); } return EXIT_SUCCESS; }
makefile文件:
.SUFFIXES: .o.c CC =gcc SRC = server.c OBJ = $(SRC: .c =.o) BIN = Sez_Server .PHONY: start start: $(OBJ) $(CC) -o $(BIN) $(OBJ) .o.c: $(SRC) $(CC) -g -Wall $@ -c $< .PHONY: clean clean: rm -f $(OBJ)
客户端:
#include<stdio.h> #include<string.h> #include<stdlib.h> #include<netinet/in.h> #include<arpa/inet.h> #include<sys/socket.h> #include<sys/types.h> #include<assert.h> #include<unistd.h> #ifndef EXIT_FAILURE #define EXIT_FAILURE -1 //exit failure #endif #ifndef EXIT_SUCCESS #define EXIT_SUCCESS 0 // exit sucessful #endif #define Port 5567 #define IPADDR "192.168.132.128" #define maxn 1024 #define ERROR_EXIT( inf ) \ do{ \ perror( inf ); \ printf("it's happened in %d \n",__LINE__); \ }while(0) ; //use the function to connect the server !! int main (int argv, char *argc[]) { int sfd = -1; char rbuf[maxn], wbuf[maxn]; // int sfd=-1 ; //socket_fd int confd = -1; //connect_fd struct sockaddr_in soaddr; if ((sfd = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) { ERROR_EXIT ("socket"); return EXIT_FAILURE; } //memset a struct memset (&soaddr, 0, sizeof (soaddr)); //int the struct sockaddr_in soaddr.sin_family = AF_INET; soaddr.sin_port = htons (Port); soaddr.sin_addr.s_addr = inet_addr (IPADDR); if ((confd = connect (sfd, (struct sockadrr *) &soaddr, sizeof (soaddr))) < 0) { ERROR_EXIT ("connect"); return EXIT_FAILURE; } printf ("connect is sucessful !\n"); while (fgets (wbuf, sizeof (rbuf), stdin) != NULL) { write (sfd, wbuf, strlen (wbuf)); read (sfd, rbuf, sizeof (rbuf)); fputs (rbuf, stdout); } close (sfd); close (confd); return EXIT_SUCCESS; }
makefile文件:
.SUFFIXES: .o.c CC =gcc SRC = client.c OBJ = $(SRC: .c =.o) BIN = Se_client .PHONY: start start: $(OBJ) $(CC) -o $(BIN) $(OBJ) .o.c: $(SRC) $(CC) -g -Wall $@ -c $< .PHONY: clean clean: rm -f $(OBJ)
效果图:
相关文章推荐
- Linux SSH远程文件/目录传输命令scp
- Linux编程系统时间的获取
- Linux中修改环境变量及生效方法
- SELinux: root 进程需要申请capability permissions吗?
- Centos下sar命令使用
- SELinux: capabilites{dac_override} 权限
- SUSE(linux)下安装GCC
- Linux命令-下载文件的工具:wget
- Linux下mysql主从配置
- lamp环境的搭建
- linux 检查定时检查程序是否运行
- Linux命令-统计文件中的字节数、字数、行数:wc
- Linux下执行的java命令重定向到文件中的方法
- CentOS下创建配置RAID1
- linux下的Makefile详解(6)
- linux下的Makefile详解(5)
- linux下的Makefile详解(3)
- centos5安装在大硬盘上面的问题
- linux设置系统日期时间
- 29个你必须知道的Linux命令