并发服务器 — —TCP服务器(epoll)

1、创建epoll对象:int epoll_create(int size);
2、往epoll对象中增加/删除某一个流的某一事件:epoll_ctl
      int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);
3、等待直到注册的事件发生:epoll_wait
      int epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout);

/*************************************************************************
	> File Name: tcpserver_select.c
	> Author: Binge
	> Mail: [email protected] 
	> Created Time: 2018年10月23日 星期二 19时56分59秒
	> 功能:将epoll函数运用在服务器中,实现I/O复用
 ************************************************************************/
#include<stdio.h>
#include<string.h>
#include<errno.h>

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

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

#define PORT 5678
#define IP "10.21.12.13"
#define MAX_FD 10000
//完成客户端监听套接字创建
int tcpserver_socket_create(void)
{
	int err;
	int listenfd;
	struct sockaddr_in server_addr;
	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");
	return listenfd;
}
//客户端数据处理函数
int socket_data_process(int sockfd)
{
	int bytes;
	char buf[128];
	bzero(buf,128);
	bytes = recv(sockfd , buf , 128 , 0);
	if(bytes < 0)
	{
		perror("recv error:\n");
		return -1;
	}
	if(bytes == 0)
	{
		return -2 ;
	}
	printf("recv from %d: %s\n",sockfd,buf);
	send(sockfd,buf,bytes,0);
	return 0;
	
}
//客户端传来数据量过大时的一种处理方式
int socket_data_process_plus(int sockfd)
{
	int bytes;
	char buf[10];
	char *s = buf;
	int flag = 1;
	int len = 0;
	bzero(buf,10);
	while(flag)
	{
		bytes = recv(sockfd , s , 10 , 0);
		if(bytes < 0)
		{
			if(errno == EAGAIN)
			{
				printf("no data readable!\n");
				break;	
			}
			else
			{
				perror("read data error:\n");
				return -1;
			}
		}
		 if(bytes == 0)
		{
			return -2 ;
		}
		if(bytes == 10)
		{
			flag = 1 ;
		}

		else
		{
			flag =0 ;
		}
		s   += bytes;
		len += bytes;
		printf("bytes:%d\n",bytes);
	}
	printf("recv from %d: %s\n",sockfd,buf);
	send(sockfd,buf,len,0);
}	

int main(int argc,char *argv[])
{
	int sockfd,listenfd;
	int err1,err2,rv;
	int epfd,fdnum,i;	
	struct epoll_event evt, events[MAX_FD];
	struct sockaddr_in client ;
	int len;
	len = sizeof(struct sockaddr_in);
	listenfd = tcpserver_socket_create();   
	epfd = epoll_create(MAX_FD);            //创建epoll对象
	if(epfd <0)
	{
		perror("epoll_create error:\n");
		return -1;
	}
	fcntl(epfd, F_SETFL, O_NONBLOCK);//设置epoll对象为非阻塞

	//向epoll对象中添加监听套接字
	evt.data.fd = listenfd;
	evt.events = EPOLLIN;
	err1 = epoll_ctl(epfd , EPOLL_CTL_ADD ,listenfd, &evt);
	if(err1 < 0)
	{
		perror("epoll_ctl error:\n");
		return -1;
	}	
	while(1)
	{
		//等待epoll中添加的事件发生
		fdnum = epoll_wait(epfd,events,MAX_FD,-1);
		if(fdnum < 0)
		{
			perror("epoll_wait error :\n");
			return -1;
		}
		for(i = 0 ; i < fdnum ; i ++)
		{
			if(events[i].data.fd == listenfd)
			{
				//处理监听套接字事件,创建通信套接字
				sockfd = accept(listenfd , (struct sockaddr *)&client, &len);
				if(sockfd < 0 )
				{
					perror("accept error :\n");
					continue ;
				}
				evt.data.fd = sockfd;
				evt.events = EPOLLIN|EPOLLET;
                //添加通信套接字至epoll
				err2 = epoll_ctl(epfd , EPOLL_CTL_ADD , sockfd ,&evt);
				if(err2 < 0)
				{
				perror("epoll_ctl error:\n");
				return -1;
				}	
			}
			else
			{
				//处理通信套接字发来的数据
				rv = socket_data_process_plus(events[i].data.fd);
				if(rv == -2)
				{
					printf("Client sockfd:%d close \n",events[i].data.fd);
					//从epoll中清除套接字
					epoll_ctl(epfd,EPOLL_CTL_DEL,events[i].data.fd,&evt);
					close(events[i].data.fd);

					continue;
				}
			/*	if(rv == -1)
				{
					epoll_ctl(epfd,EPOLL_CTL_DEL,events[i].data.fd,&evt);
					close(events[i].data.fd);
					printf("%d socket_data_process error:\n",events[i].data.fd);
					close(epfd);
					close(listenfd);

				}*/
			}
		}
	}
}

猜你喜欢

转载自blog.csdn.net/weixin_42039602/article/details/83660357
今日推荐