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);
}*/
}
}
}
}