linux c IO复用之epoll模型实例 实现服务器与多个客户端进行通信

//util.h
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/time.h>
#include<arpa/inet.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<sys/epoll.h>
#define backlogs 10
#define BUF_SIZE  150
int Socket(int domain,int type,int protocol)
{
	int fd=socket(domain,type,protocol);
	if(fd==-1)
		return -1;
	return fd;
}
int Bind(int sockfd,const struct sockaddr *addr,socklen_t addrlen)
{
	int ret=bind(sockfd,addr,addrlen);
	if(ret==-1)
		return -1;
	return ret;
}
int Listen(int sockfd,int backlog)
{
	int ret=listen(sockfd,backlog);
	if(ret==-1)
		return -1;
	return ret;
}
int start_up(const char* ip,int port)
{
	int fd=Socket(AF_INET,SOCK_STREAM,0);
	struct sockaddr_in ser_addr;
	ser_addr.sin_family=AF_INET;
	ser_addr.sin_port=htons(port);
	ser_addr.sin_addr.s_addr=inet_addr(ip);
	int on=1;
	setsockopt(fd,SOL_SOCKET,SO_REUSEADDR,&on,sizeof(int));
	socklen_t addrlen=sizeof(struct sockaddr);
	Bind(fd,(struct sockaddr*)&ser_addr,addrlen);
	Listen(fd,backlogs);
	return fd;
}
///
//ser.c
#include"util.h"
#define OPEN_MAX 5000
int main(int argc,char *argv[])
{
	int i,listenfd,connfd,sockfd;
	int n,num=0;
	ssize_t nready,efd,res;
	char buf[BUF_SIZE],str[INET_ADDRSTRLEN];//16
	socklen_t clilen;
	struct sockaddr_in cliaddr,servaddr;
	struct epoll_event tep,ep[OPEN_MAX];//tep:epoll_ctl参数 ep: epoll_wait()参数
	listenfd=start_up(argv[1],atoi(argv[2]));
	efd=epoll_create(OPEN_MAX);          //创建epoll模型,efd指向红黑树根节点
	if(efd==-1)
	{
		perror("epoll_create error!\n");
		exit(1);
	}
	tep.events=EPOLLIN;   tep.data.fd=listenfd; //指定listenfd的监听事件为"读"
	
	res=epoll_ctl(efd,EPOLL_CTL_ADD,listenfd,&tep);//将listenfd及对应的结构体设置到树上, 
                                                     //efd可找到该树
	if(res==-1)
	{
		perror("epoll_ctl error!\n");
		exit(1);
	}
	while(1)
	{
    //epoll为server阻塞监听事件,ep为struct epoll_event类型数组,OPEN_MAX为数组容量,-1表示永                                                                
                                                                           //久阻塞
		nready=epoll_wait(efd,ep,OPEN_MAX,-1);
		if(nready==-1)
		{
			perror("epoll_wait error!!!\n");
			exit(1);
		}
		for(i=0;i<nready;i++)
		{
			if(!(ep[i].events & EPOLLIN))
				continue;
			if(ep[i].data.fd==listenfd)
			{
				clilen=sizeof(struct sockaddr);
				connfd=accept(listenfd,(struct sockaddr*)&cliaddr,&clilen);
				printf("Received from %s at PORT %d\n",
						inet_ntoa(cliaddr.sin_addr),ntohs(cliaddr.sin_port));
				printf("cfd %d------client %d\n",connfd,++num);
				tep.events=EPOLLIN; tep.data.fd=connfd;
				res=epoll_ctl(efd,EPOLL_CTL_ADD,connfd,&tep);
				if(res==-1)
				{
					perror("epoll_ctl error!\n");
					exit(1);
				}
			}
			else                    //不是listenfd  而是接发数据
			{
				sockfd=ep[i].data.fd;
				n=recv(sockfd,buf,strlen(buf)+1,0);
				if(n==0)     //说明客户端关闭连接
				{
					res=epoll_ctl(efd,EPOLL_CTL_DEL,sockfd,NULL);//将该文件描述符从红黑树中摘除	
			/*		if(res==-1)
					{
						perror("epoll_ctl error!!!\n");
						exit(1);
					}*/
					close(sockfd);            //关闭与客户端的连接
					printf("client[%d] closed connection!!!\n",sockfd);
				}
				else if(n<0)//出错
				{
					perror("read n<0 error!!!\n");
					res=epoll_ctl(efd,EPOLL_CTL_DEL,sockfd,NULL);
					close(sockfd);
				}
				else
				{
					for(i=0;i<n;i++)
						buf[i]=toupper(buf[i]);
					send(sockfd,buf,n,0);
				}
			}
		}
	}
	close(listenfd);
	close(efd);
	return 0;
}

///
//cli.c
#include"util.h"
int main(int argc,char *argv[])
{
	char sendbuf[128];
	char recvbuf[128];
	socklen_t addrlen=sizeof(struct sockaddr);
	int cli_fd=socket(AF_INET,SOCK_STREAM,0);
	if(cli_fd==-1)
		return -1;
	struct sockaddr_in seraddr;
	seraddr.sin_family=AF_INET;
	seraddr.sin_port=htons(atoi(argv[2]));
	seraddr.sin_addr.s_addr=inet_addr(argv[1]);
	int ret=connect(cli_fd,(struct sockaddr*)&seraddr,addrlen);
	if(ret==-1)
	{
		perror("connect error!\n");
		return -1;
	}
	else
		printf("success\n");
	while(1)
	{
		printf("Cli:>");
		scanf("%s",sendbuf);
		send(cli_fd,sendbuf,strlen(sendbuf)+1,0);
		recv(cli_fd,recvbuf,128,0);
		printf("From Self Cli:%s\n",recvbuf);
	}
	close(cli_fd);
	return 0;
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值