• 31网络通信之Select模型


    多路复用并发模型  -- select

    #include<sys/select.h>

    #include<sys/time.h>

    int select(int maxfd,  fd_set *readset, fd_set *writeset,  fd_set *exceptset,  struct timeval *timeout)

    maxfd    监控的套接字最大值 + 1

    readset  集合中任意描述字准备好读,则返回

    writeset  集合中任意描述字准备好写,则返回

    exceptset 集合中任意描述字有异常等待处理,则返回

    timeout     超时则返回(NULL 则一直等待,0 则立即返回)

    返回值 =0 超时, 返回值<0 错误,返回值>0正常

    多路复用并发模型 -- select

    FD_ZERO(fd_set  *fdset)   

    清空描述符集合

    FD_SET(int fd,  fd_set *fdset) 

    增加fd 到集合中, 事实上就是把某个bit位置位

    FD_CLR(int fd,  fd_set *fdset)  

    从集合中清除fd, 事实上就是把某个bit位清除置位

    int  FD_ISSET(int fd,  fd_set  *fdset)  

    描述字是否准备好

    多路复用并发模型  -- select

    优点:

    通过IO复用,支持交互式输入

    通过IO复用,可以同时监听 UDP 和 TCP

    相比比多线程, 系统开销大大减少,

    缺点:

    每次调用 select 都需要把fd集合从用户态拷贝到内核态,fd很多时开销很大

    调用 select 需要内核遍历 fd, fd 很多时开销很大

    select 支持文件描述符监视有数量限制,默认 1024

    服务器端代码:

    #include<stdio.h>
    #include<unistd.h>
    #include<string.h>
    
    #include<sys/socket.h>
    #include<netinet/in.h>
    #include<arpa/inet.h>
    
    #include<sys/select.h>
    #include<sys/time.h>
    
    #define SRV_PORT 0xabcd
    #define MAX_CONN 3
    
    void RcvMsg(int fds[], int index, int *pnConn)
    {
    	char szBuf[1024] = {0};
    	int iRet;
    
    	iRet = read(fds[index], szBuf, 1024);
    	if (iRet < 0)
    	{
    		perror("Fail to read!");
    	}
    	else if (iRet == 0)
    	{
    		//disconnect.  remove fd from fds
    		printf("[%d]Disconnect...
    ", fds[index]);
    		close(fds[index]);
    
    		int j;
    		for (j=index; j < *pnConn - 1; j++)
    		{
    			fds[j] = fds[j+1];
    		}
    		(*pnConn)--;
    	}
    	else
    	{
    		printf("[%d]Recv:%s
    ", fds[index], szBuf);
    	}
    
    	return;
    }
    
    void TcpServer()
    {
    	int fd;
    	int iRet;
    	struct sockaddr_in addr;
    	socklen_t addrlen = sizeof(addr);
    
    	fd = socket(PF_INET, SOCK_STREAM, 0);
    	if (fd < 0)
    	{
    		perror("Fail to socket!");
    		return;
    	}
    
    	addr.sin_family = AF_INET;
    	addr.sin_addr.s_addr = htonl(INADDR_ANY);
    	addr.sin_port = htons(SRV_PORT);
    
    	iRet = bind(fd, (struct sockaddr*)&addr, addrlen);
    	if (iRet)
    	{
    		perror("Fail to bind!");
    		close(fd);
    		return;
    	}
    
    	iRet = listen(fd, 100);
    	if (iRet)
    	{
    		perror("Fail to listen!");
    		close(fd);
    		return;
    	}
    
    	fd_set fdset;
    	int maxfd = fd;
    	int fds[MAX_CONN]; //client fd;
    	int nConn = 0;         //client fd num.
    	int i;
    	int clientfd;
    	struct sockaddr_in srcaddr;
    	char szMsg[100];
    
    	while(1)
    	{
    		FD_ZERO(&fdset);
    		FD_SET(fd, &fdset);
    		
    		for (i=0; i<nConn; i++)
    		{
    			FD_SET(fds[i], &fdset);//add client fd to fdset for monitor
    		}
    
    		fprintf(stderr, "Send:");
    		scanf("%s", szMsg);
    		for (i=0; i<nConn; i++)
    		{
    			write(fds[i], szMsg, strlen(szMsg));
    		}
    
    		iRet = select(maxfd+1, &fdset, NULL, NULL, NULL);	
    		if (iRet < 0)
    		{
    			perror("Fail to select!");
    			break;
    		}
    		else if (iRet == 0)
    		{
    			//timeout
    		}
    		else
    		{
    			if (FD_ISSET(fd, &fdset))
    			{
    				clientfd = accept(fd, (struct sockaddr*)&srcaddr, &addrlen);
    				if (clientfd < 0)
    				{
    					perror("Fail to accept!");
    					break;
    				}
    				if (nConn == MAX_CONN)
    				{
    					char szTip[] = "Over connect, please wait...";
    					write(clientfd, szTip, sizeof(szTip));
    					printf("Connect over!
    ");
    					close(clientfd);
    				}
    				else
    				{
    					char szTip[] = "Welcome!";
    					write(clientfd, szTip, sizeof(szTip));
    
    					printf("[%d]New connection form %s:%d
    ", clientfd, 
    						inet_ntoa(srcaddr.sin_addr), ntohs(srcaddr.sin_port));
    					
    					fds[nConn] = clientfd;
    					nConn++;
    				
    					if (clientfd > maxfd)
    					{
    						maxfd = clientfd;
    					}
    				}
    			}
    			
    			for (i=0; i<nConn; i++)
    			{
    				if (FD_ISSET(fds[i], &fdset))
    				{
    					RcvMsg(fds, i, &nConn);			
    				}
    			}
    				
    				
    		}
    	}
    	
    	close(fd);
    }
    
    int main()
    {
    	TcpServer();
    	
    	return 0;
    }
    

      

  • 相关阅读:
    Codeforces 994B. Knights of a Polygonal Table
    Codeforces 994A. Fingerprints
    Codeforces 988F. Rain and Umbrellas
    51nod 1158 全是1的最大子矩阵(单调栈 ,o(n*m))
    51nod 1102 面积最大的矩形 && 新疆大学OJ 1387: B.HUAWEI's billboard 【单调栈】+【拼凑段】(o(n) 或 o(nlog(n))
    Codeforces 988E. Divisibility by 25
    【复习资料】单片机与嵌入式系统原理及应用
    Codeforces 723D. Lakes in Berland
    Codeforces 986A. Fair(对物品bfs暴力求解)
    Codeforces 986B. Petr and Permutations(没想到这道2250分的题这么简单,早知道就先做了)
  • 原文地址:https://www.cnblogs.com/gd-luojialin/p/10371582.html
Copyright © 2020-2023  润新知