#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; } } }
}
|