#include <sys/epoll.h>
#include <unistd.h>
//#include <linux/tcp.h>
#include <netinet/tcp.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <vector>
#include "../../Common/TypeDefine.h"
#include "../../Common/MemPool.h"


int32 set_nonblocking(int fd)
  {
int32 oflags;
if ((oflags = fcntl(fd, F_GETFL, 0)) == -1)
return errno;
if (fcntl(fd, F_SETFL, oflags | O_NONBLOCK) == -1)
return errno;
return 0;
}



int32 epollDel(int epfd,struct epoll_event *pEpev)
  {
return epoll_ctl(epfd, EPOLL_CTL_DEL,pEpev->data.fd, pEpev);
}

int32 main(int argc,char *argv[])
  {
//创建套接字
int32 listenfd = socket(AF_INET,SOCK_STREAM,0);
if(listenfd < 0)
return -1;
//将套接字设为异步
int32 ret= set_nonblocking(listenfd);
if(ret != 0)
return -1;
int32 flag = 1;
setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &flag, sizeof(flag)); //设置地址端口复用,服务器快速重起
// 设置SO_LINGER选项(防范CLOSE_WAIT挂住所有套接字)
struct linger optval1;
optval1.l_onoff = 1;
optval1.l_linger = 60;
setsockopt(listenfd, SOL_SOCKET, SO_LINGER, &optval1, sizeof(struct linger));
//创建epoll
int32 maxSize = getdtablesize(); //返回某个进程所能打开的最大的文件数
int32 epfd = epoll_create(maxSize);//创建一个epoll的句柄
if(epfd==-1)
return -1;
printf("create epoll,maxSize=%d\n",maxSize);
//事件注册
struct epoll_event epev;
epev.events = EPOLLIN| EPOLLET;
epev.data.fd = listenfd;
int32 err = epoll_ctl(epfd, EPOLL_CTL_ADD, listenfd, &epev);
printf("register epoll event finish!\n");
//绑定端口
printf("start bind,port=%d\n",9300);
struct sockaddr_in saddr;
memset(&saddr,0,sizeof(struct sockaddr_in));
saddr.sin_family = AF_INET;
saddr.sin_port = htons(9300);
saddr.sin_addr.s_addr = inet_addr("127.0.0.1");
ret = bind(listenfd,(struct sockaddr *)&saddr,sizeof(struct sockaddr_in));
if(ret < 0)
 {
return -1;
}

ret = listen(listenfd,500);

printf("listen finish!\n");

//循环
int32 nev, i, millisecs = 200;
struct epoll_event m_evs[100];
CHAR buf[4096];
while(1)
 {
if ((nev = epoll_wait(epfd, m_evs, 100, millisecs)) < 0)
 {
if (errno == EINTR)
continue;
else
return -1;
}
 for (i = 0; i < nev; i++) {
printf("epoll wait event count=%d\n",nev);
if (m_evs[i].data.fd == listenfd)
 {
struct sockaddr_in addr;
socklen_t len = sizeof(addr);
int32 connfd = accept(listenfd,(struct sockaddr *)&addr, &len);
printf("accept client fd=%d\n",connfd);
if (connfd < 0)
 {
if (errno == EWOULDBLOCK || errno == ECONNABORTED)
 {
printf("Failed to accept new connection (%s).\n", strerror(errno));
continue;
}
else
 {
//error
printf("Failed to accept new connection (%s).\n", strerror(errno));
continue;
}
}
//将套接字设为异步
 if (set_nonblocking(connfd) != 0) {
close(connfd);
return -1;
}
int32 on=1;
setsockopt(connfd, IPPROTO_TCP, TCP_NODELAY,(void *)&on,(socklen_t)sizeof(on));
struct sockaddr_in clientaddr;
CHAR *str = inet_ntoa(clientaddr.sin_addr);
printf("accapt a connection from %s\n",str);
//设置用于读操作的文件描述符
struct epoll_event ev;
ev.data.fd=connfd;
//设置用于注测的读操作事件
ev.events=EPOLLIN|EPOLLET;
//ev.data.ptr = new int8[4097];
//注册ev
epoll_ctl(epfd,EPOLL_CTL_ADD,connfd,&ev);
printf("accept client register epoll event!\n");
}
else if(m_evs[i].events&EPOLLIN)//如果是已经连接的用户,并且收到数据,那么进行读入
 {
printf("EVENT->EPOLLIN\n");
//先屏掉测试
//continue;
//如果套接字错误
int32 sockfd;
if ( (sockfd = m_evs[i].data.fd) < 0)
 {
printf("error socket!\n");
continue;
}
int32 rv = 0;
BOOL bClose = FALSE;
int32 totalRv = 0;
 char buf[4097] = {0};
const int32 maxRead = 10;
rv = read(m_evs[i].data.fd,buf+totalRv,maxRead-totalRv);
while((rv > 0) || (rv < 0 && errno == EINTR))
 {
if(rv>0)
 {
totalRv += rv;
printf("read context=[%s]\n",buf);
}
printf("read current size = %d,total size=%d\n",rv,totalRv);
//缓冲区读满
if(totalRv >= maxRead)
 {
break;
}
rv = read(m_evs[i].data.fd,buf+totalRv,maxRead-totalRv);
}
//对端连接关闭
//EAGAIN没数据,EINTR被中断
if(rv == 0 ||
(rv < 0 && errno != EAGAIN && errno!=EINTR) )
 {
printf("read fail ,socket will close!\n");
epollDel(epfd,&m_evs[i]);
close(m_evs[i].data.fd);
m_evs[i].data.fd = -1;
bClose = TRUE;
}
else
 {
//往对端发送写入数据事件
struct epoll_event ev;
ev.data.fd=m_evs[i].data.fd;
//设置用于注测的读操作事件
//ev.events=EPOLLIN|EPOLLOUT|EPOLLET;
ev.events = m_evs[i].events | EPOLLOUT|EPOLLET;
//将事件改为写
int32 ret = epoll_ctl(epfd,EPOLL_CTL_MOD,ev.data.fd,&ev);
printf("end add event ret = %d\n",ret);
if(ret == -1)
 {
printf("Failed to accept new connection (%s),errno=%d.\n", strerror(errno),errno);
}
}
}
else if(m_evs[i].events&EPOLLOUT)
 {
printf("EVENT->EPOLLOUT\n");
//先不写数据
//continue;
int32 sockfd = m_evs[i].data.fd;
 char buffer[4096]= {0};
CString str ;
for(int j=0;j<1;j++)
 {
str += "0123456789";
}
strncpy(buffer,str.c_str(),4095);
char *strPos = buffer;
int pos = 0;
int len = strlen(buffer);
int rv = write(sockfd,buffer+pos,len-pos);
while((rv >= 0) || (rv < 0 && errno == EINTR))
 {
printf("write current size = %d,total size = %d\n",rv,pos);
if(rv > 0)
 {
printf("write data size=%d\n",rv);
}
//数据写完跳出
if(pos+1==len)
break;
if(rv>0)
pos += rv;
if(len - pos <=0)
 {
printf("send data finish! size = %d\n",len);
break;
}
rv = write(sockfd,buffer+pos,len-pos);
}
if(rv < 0 && errno != EAGAIN && errno != EINTR)
 {
printf("write fail ,socket will close!\n");
epollDel(epfd,&m_evs[i]);
close(m_evs[i].data.fd);
m_evs[i].data.fd = -1;
}
}
else if (m_evs[i].events&EPOLLERR || m_evs[i].events&EPOLLHUP)
 {
printf("events error ,socket will close!\n");
epollDel(epfd,&m_evs[i]);
close(m_evs[i].data.fd);
m_evs[i].data.fd = -1;
}
}
}

}
|