并发服务器 — — I/O复用(select)

 简单通过select函数实现I/O复用完成并发服务器的编写:

功能:将select函数运用在服务器中,实现I/O复用
#include<stdio.h>
#include<string.h>
#include<errno.h>

#include<unistd.h>
#include<sys/times.h>
#include<sys/types.h>
#include<sys/select.h>

#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>

#define PORT 5678
#define IP "10.21.12.13"
int main(int argc,char *argv[])
{
	int sockfd,listenfd;
	int err;
	int client_addrlen,bytes;
	fd_set globe_nfds,current_nfds;
	int nfds,i;
	char buf[128];
	struct sockaddr_in server_addr, client_addr;
	client_addrlen = sizeof(struct sockaddr_in);
	listenfd = socket(AF_INET,SOCK_STREAM,0);
	if(listenfd == -1)
	{
		printf("creat socket error,errno = %d\n",errno);
		return -1;
	}
	memset(&server_addr,0,sizeof(struct sockaddr_in));
	server_addr.sin_family  = AF_INET;
	server_addr.sin_port = htons(PORT);
	server_addr.sin_addr.s_addr = inet_addr(IP);//32bit IPv4 Address
	err = bind(listenfd ,(struct sockaddr *)&server_addr,sizeof(struct sockaddr));
	if(err == -1)
	{
		printf("bind error,errno is %d\n",errno);
		close(listenfd);
		return -1;
	}
	printf("bind success!\n");
	if(listen(listenfd ,10) == -1)
	{
		printf("listen error,errno is %d\n",errno);
		close(listenfd);
		return -1;
	}
	printf("listening...\n");
	FD_ZERO(&globe_nfds);
	FD_SET(listenfd,&globe_nfds);
	nfds = listenfd;
	while(1)
	{
		current_nfds = globe_nfds;

		if(select(nfds+1,&current_nfds,NULL,NULL,NULL)<0)
		{
			perror("select error.\n");
			printf("errno:%d\n",errno);
			close(listenfd);
			return -1;
		}
		for(i=0;i<= nfds;i++)
		{
			if(FD_ISSET(i,&current_nfds))
			{

				if(i == listenfd)
				 {
					sockfd = accept(listenfd,(struct sockaddr*)&client_add, &client_addrlen);
					if(sockfd<0)
					{	
       					peror("accept error.\n");		
						close(listenfd);
						return -1;
					}	
					nfds = nfds>sockfd?nfds:sockfd;
    				FD_CLR(listenfd,&current_nfds);		
					FD_SET(sockfd,&globe_nfds);
				 }
				else
				{
					bytes = recv(i,buf,128,0);
					if(bytes<0)
					{
						perror("recv data error.");
						printf("errornum:%d\n",errno);
						close(i);
						return -1;
					}
					if(bytes == 0)
					{
						printf("client closed!\n");
						FD_CLR(i,&globe_nfds);
						close(i);
						continue;
					}
					printf("recv data from client :%s\n",buf);
					send(i,buf,strlen(buf),0);
					bzero(buf,128);
					}
			}
		}
	}	

}

升级版:提高效率的一种方式

	> 功能:将select函数运用在服务器中,实现I/O复用
 ************************************************************************/
#include<stdio.h>
#include<string.h>
#include<errno.h>

#include<unistd.h>
#include<sys/times.h>
#include<sys/types.h>
#include<sys/select.h>

#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>

#define PORT 5678
#define IP "10.21.12.13"
int main(int argc,char *argv[])
{
	int sockfd,listenfd;
	int err;
	int client_addrlen,bytes;
	fd_set globe_nfds,current_nfds;
	int nfds,i;
	char buf[128];
	char clientfd[FD_SETSIZE];
	printf("FD_SETSIZE=%d\n",FD_SETSIZE);
	struct sockaddr_in server_addr, client_addr;
	client_addrlen = sizeof(struct sockaddr_in);
	listenfd = socket(AF_INET,SOCK_STREAM,0);
	if(listenfd == -1)
	{
		printf("creat socket error,errno = %d\n",errno);
		return -1;
	}
	memset(&server_addr,0,sizeof(struct sockaddr_in));
	server_addr.sin_family  = AF_INET;
	server_addr.sin_port = htons(PORT);
	server_addr.sin_addr.s_addr = inet_addr(IP);//32bit IPv4 Address
	err = bind(listenfd ,(struct sockaddr *)&server_addr,sizeof(struct sockaddr));
	if(err == -1)
	{
		printf("bind error,errno is %d\n",errno);
		close(listenfd);
		return -1;
	}
	printf("bind success!\n");
	if(listen(listenfd ,10) == -1)
	{
		printf("listen error,errno is %d\n",errno);
		close(listenfd);
		return -1;
	}
	printf("listening...\n");
	FD_ZERO(&globe_nfds);
	FD_SET(listenfd,&globe_nfds);
	nfds = listenfd;
	//初始化套接字数组
	for(i = 0 ;i < FD_SETSIZE ; i ++)
		clientfd[i] = -1 ;
	while(1)
	{
		current_nfds = globe_nfds;
		if(select(nfds+1,&current_nfds,NULL,NULL,NULL)<0)
		{
			perror("select error.\n");
			printf("errno:%d\n",errno);
			close(listenfd);
			return -1;
		}
		//若是监听套接字则等待来自客户端的连接
		if(FD_ISSET(listenfd,&current_nfds))
		{
			sockfd = accept(listenfd,(struct sockaddr*)&client_addr,&client_addrlen);
			if(sockfd<0)
			{
				 perror("accept error.\n");
				 close(listenfd);
				 return -1;
			}
				nfds = nfds>sockfd?nfds:sockfd;
				FD_CLR(listenfd,&current_nfds);
				FD_SET(sockfd,&globe_nfds);//将新建立的通信连接套接字加入套接字集
				for(i = 0 ; i < nfds ;i ++)
				{
					if(-1 == clientfd[i])
					{
						clientfd[i] = sockfd;
						break;
					}
				}
		
		}
		for(i = 0 ; i <= nfds ; i++ )
		{
			if(clientfd[i] == -1)
			{
				continue;
			}
			if(FD_ISSET(clientfd[i], &current_nfds))
			{
				bytes = recv(clientfd[i],buf,128,0);
				if(bytes<0)
				{
					perror("recv data error.");
					printf("errornum:%d\n",errno);
					close(clientfd[i]);
					return -1;
				}
				if(bytes == 0)
				{
				printf("client %d has closed!\n",clientfd[i]);
				FD_CLR(clientfd[i],&globe_nfds);
				clientfd[i] = -1;
				close(clientfd[i]);
				continue;
				}	
			printf("recv data from client :%s\n",buf);
			send(clientfd[i],buf,strlen(buf),0);
			bzero(buf,128);
			
			}
		}
	}	

}

猜你喜欢

转载自blog.csdn.net/weixin_42039602/article/details/83627356