测试代码
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/resource.h>
#include <sys/epoll.h>
const int ep_sock_num = 20;
struct epoll_event ep_wait_array[20];
const int listen_port = 7890;
int sock_listener = -1;
int epFd = -1;
int setnonblocking(int fd)
{
int opts = fcntl(fd, F_GETFL);
if(opts < 0)
{
perror("1mfunc fcntl");
return -1;
}
opts |= O_NONBLOCK;
if(fcntl(fd, F_SETFL, opts) < 0)
{
perror("2func fcntl");
return -1;
}
return 1;
}
int ep_add_fd(int fd)
{
if(fd < 0 || epFd < 0)
{
printf("ep_add_fd error fd=%d, epFd=%d!\n", fd, epFd);
return -1;
}
struct epoll_event event;
int ret = setnonblocking(fd);
if(ret < 0)
{
printf("ep_add_fd error2 !\n");
return -1;
}
event.data.fd = fd;
//event.events = EPOLLIN|EPOLLET;
//对端正常关闭触发EPOLLIN、EPOLLRDHUP
//EPOLLERR 表示对应的文件描述符发生错误;
//EPOLLHUP
//表示对应的文件描述符被挂断;譬如收到RST包。在注册事件的时候这个事件是默认添加。
event.events = EPOLLET|EPOLLIN|EPOLLERR;//EPOLLOUT
ret = epoll_ctl(epFd, EPOLL_CTL_ADD, fd, &event);
if(ret < 0)
{
perror("epoll_ctl");
return -1;
}
return 0;
}
int ep_add_fd_out(int fd)
{
if(fd < 0 || epFd < 0)
{
printf("ep_add_fd error!\n");
return -1;
}
struct epoll_event event;
event.data.fd = fd;
event.events = EPOLLET|EPOLLIN|EPOLLERR|EPOLLOUT;
int ret = epoll_ctl(epFd, EPOLL_CTL_MOD, fd, &event);
if(ret < 0)
{
perror("epoll_ctl");
return -1;
}
return 0;
}
int ep_del_fd_out(int fd)
{
struct epoll_event event;
if(epFd <= 0)
return -1;
event.data.fd = fd;
event.events = EPOLLET|EPOLLIN|EPOLLERR;
if(0 != epoll_ctl(epFd,EPOLL_CTL_MOD,fd,&event))
{
int ierrno = errno;
perror("epoll_ctl");
return ierrno;
}
return 0;
}
int ep_wait_fds()
{
return epoll_wait(epFd, ep_wait_array, 20, -1);
}
int create_sock()
{
epFd = epoll_create(ep_sock_num );
if(epFd < 0)
{
perror("epoll_create");
exit(1);
}
sock_listener = socket(AF_INET, SOCK_STREAM, 0);
if(sock_listener < 0)
{
perror("func socket");
exit(-1);
}
struct sockaddr_in server_addr;
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(listen_port);
server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
int flag = 1, len = sizeof(int);
if( setsockopt(sock_listener, SOL_SOCKET, SO_REUSEADDR, &flag, len) == -1)
{
perror("setsockopt()");
exit(1);
return -1;
}
if (bind(sock_listener, (struct sockaddr *) &server_addr, sizeof(struct sockaddr)) == -1)
{
perror("bind()");
exit(1);
return -1;
}
else
{
printf("IP and port bind OK!\n");
}
int iRet = listen(sock_listener, 0);//监听
if (0 !=iRet)
{
perror("listen()");
exit(1);
return -1;
}
iRet = ep_add_fd(sock_listener);
if(iRet < 0)
{
printf("mFunc sock_listener error!\n");
exit(-1);
return -1;
}
return sock_listener;
}
char arrRecvBuf[1024];
char *pSendBuf = "end\n";
int main(int argc, char *argv[])
{
int n = 1024;
int iRet = create_sock();
if(iRet < 0)
{
printf("mFunc create_sock error!\n");
}
printf("create listenning socket:%d ok!\n", sock_listener);
struct sockaddr_in local, remote;
socklen_t addr_len =sizeof(struct sockaddr_in);
while(1)
{
iRet = ep_wait_fds();
if(iRet < 0)
{
printf("mfunc ep_wait_fd errno:", iRet);
}
else if(iRet == 0)
{
printf("ep wait timeout!\n");
continue;
}
int i=0;
for(i=0; i<iRet; i++)
{
printf("\n\nwaiting return %d socket event!\n", iRet);
int fd = ep_wait_array[i].data.fd;
if(fd == sock_listener)
{
int newfd = 0;
while((newfd = accept(fd, (struct sockaddr *)&remote, &addr_len)) > 0)
{
printf("new fd:%d addr:%s,port:%d connecting success!\n",
newfd, inet_ntoa(*((struct in_addr*)&remote.sin_addr)), remote.sin_port);
iRet = ep_add_fd(newfd);
}
printf("accept error! continue!\n");
continue;
}
if(ep_wait_array[i].events & EPOLLIN)
{
ep_add_fd_out(fd);
printf("----------------------------------epoll EPOLLIN socket:%d\n",fd);
int iErrIn = 0;
int iRecvLen = 0;
int nread = 0;
int iRecvErrno = 0;
while(1)
{
char *pRecvBuf=arrRecvBuf;
while ( (n > 0) && ((nread = recv(fd,pRecvBuf,n,0)) >0 ) )
{
printf("---test---recv len:%d\n",nread);
iRecvLen += nread;
pRecvBuf += nread;
n = n-nread;
}
if(iRecvLen > 0)
{
write(1, arrRecvBuf, iRecvLen);
if(strncmp(arrRecvBuf, "exit", 4) == 0)
{
close(fd);
break;
}
}
if (-1==nread)
{
if(errno != EAGAIN)
{//出致命错误
perror("recv");
iErrIn = 1;
}
break;
}
if(0 == nread)
{//socket被关闭
printf("----------epoll socket:%d 对方关闭\n",fd);
iErrIn = 2;
break;
}
}
if( 0 != iErrIn )
{//出错或者是对方关闭socket,在这清理数据,redis、socket map
close(fd);
continue;
}
}//if
//send event
if(ep_wait_array[i].events & EPOLLOUT)
{
printf("++++++++++++++++++++++++++++++++++++++epoll EPOLLOUT socket:%d\n",fd);
int len = 0;
while((len = send(fd, pSendBuf, 5, 0)) > 0 )
{
if(len == 5)
{
break;
}
}
if(errno != EAGAIN)
{
perror("send ");
}
}
//error event
if( (ep_wait_array[i].events & EPOLLERR) || (ep_wait_array[i].events & EPOLLHUP) )
{
printf("----------触发epoll事件EPOLLERR或者EPOLLHUP <socket出现错误>,socket:%d \n",fd);
close(fd);
continue;
}
}//for
}//while
printf("main exit!\n");
return 0;
}