#include "epollserver.h"
#include <assert.h>
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#include <fcntl.h>
#define MAX_EPOLL_EVENT_COUNT 30000
#define EPOLL_WAIT_TIMEOUT 1000
namespace lyf
{
EpollServer::EpollServer(void)
{
epfd = -1;
listenfd = -1;
port = 6880;
epollEventList = new epoll_event[MAX_EPOLL_EVENT_COUNT];
assert(epollEventList != NULL);
thread = 0;
stop = true;
}
EpollServer::~EpollServer(void)
{
if (epollEventList)
{
delete epollEventList;
epollEventList = NULL;
}
}
int EpollServer::SetNonblocking(int fd)
{
int opts;
opts = fcntl(fd, F_GETFL);
if(opts < 0)
{
printf("fcntl(fd, GETFL)");
return -1;
}
opts = opts|O_NONBLOCK;
if(fcntl(fd, F_SETFL, opts) < 0)
{
printf("fcntl(fd, SETFL, opts)");
return -1;
}
return 0;
}
void* EpollServer::WorkProcProxy(void * param)
{
EpollServer * p = (EpollServer*) param;
p->WorkProc();
}
int EpollServer::WorkProc(void)
{
listenfd = socket(AF_INET, SOCK_STREAM, 0);
if (listenfd == -1)
{
printf("create socket failed\n");
return -1;
}
int opt = 1;
setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
SetNonblocking(listenfd);
sockaddr_in si;
si.sin_family = AF_INET;
si.sin_port = htons(port);
si.sin_addr.s_addr = htonl(INADDR_ANY);
if (0 != bind(listenfd, (sockaddr*)&si, sizeof(si)))
{
printf("bind socket failed, %s\n", strerror(errno));
close(listenfd);
return -1;
}
if (0 != listen(listenfd, 1024))
{
printf("listen socket failed, %s\n", strerror(errno));
close(listenfd);
return -1;
}
epfd = epoll_create(MAX_EPOLL_EVENT_COUNT);
if (epfd == -1)
{
printf("epoll create failed, %s\n", strerror(errno));
close(listenfd);
return -1;
}
epoll_event e;
e.events = EPOLLIN | EPOLLOUT | EPOLLET;
e.data.fd = listenfd;
if (epoll_ctl(epfd, EPOLL_CTL_ADD, listenfd, &e) < 0)
{
printf("epoll ctrl failed, %s\n", strerror(errno));
close(listenfd);
}
while (!stop)
{
int count = epoll_wait(epfd, epollEventList, MAX_EPOLL_EVENT_COUNT, EPOLL_WAIT_TIMEOUT);
if (count < 0)
{
printf("epoll wait failed, %s\n", strerror(errno));
exit(-1);
}
for (int i=0; i<count; i++)
{
epoll_event * p = &epollEventList[i];
if (p->events & (EPOLLERR | EPOLLHUP))
{
printf("epoll events error, %s\n", strerror(errno));
Connection * c = (Connection*)p->data.ptr;
if (c)
{
OnClose(c);
}
continue;
}
HandleEvent(*p);
}
}
if (listenfd != -1)
{
close(listenfd);
listenfd = -1;
}
if (epfd != -1)
{
close(epfd);
epfd = -1;
}
std::list<Connection*>::iterator it = connectionList.begin();
for (; it!=connectionList.end(); it++)
{
Connection * c = *it;
if (c && c->fd!=-1)
{
close(c->fd);
}
delete c;
}
return 0;
}
int EpollServer::HandleEvent(epoll_event & e)
{
if (e.data.fd == listenfd)
{
sockaddr_in si;
socklen_t sl = sizeof(si);
int fd = accept(listenfd, (struct sockaddr*)&si, &sl);
if (fd == -1)
{
printf("accept socket failed, %s\n", strerror(errno));
return -1;
}
//设置fd为非阻塞
SetNonblocking(fd);
Connection * c = new Connection;
c->fd = fd;
c->closed = 0;
c->remoteAddress = si;
epoll_event _e;
_e.data.fd = fd;
_e.data.ptr = c;
_e.events = EPOLLIN|EPOLLOUT|EPOLLET;
if (0 != epoll_ctl(epfd, EPOLL_CTL_ADD, fd, &_e))
{
printf("epoll ctl add failed, %s\n", strerror(errno));
close(fd);
c->fd = -1;
c->closed = 1;
delete c;
return -1;
}
else
{
OnAccept(c);
}
}
else
{
Connection * c = (Connection*)e.data.ptr;
if (e.events & EPOLLIN && !c->closed)
{
OnRead(c);
}
if (e.events & EPOLLOUT && !c->closed)
{
OnWrite(c);
}
}
}
int EpollServer::OnAccept(Connection * c)
{
connectionList.push_back(c);
printf("a client connect to server: %d.\n", c->fd);
return 0;
}
int EpollServer::OnClose(Connection * c)
{
printf("a client disconnect to server: %d.\n", c->fd);
epoll_event e;
e.data.fd = c->fd;
e.events = EPOLLIN|EPOLLOUT|EPOLLET;
if (0 != epoll_ctl(epfd, EPOLL_CTL_DEL, c->fd, &e))
{
printf("epoll event del failed, %s\n", strerror(errno));
}
close(c->fd);
c->fd = -1;
c->closed = 1;
c->recvBuffer.clear();
c->sendBuffer.clear();
connectionList.remove(c);
//delete c;
return 0;
}
int EpollServer::OnError(Connection * c)
{
return 0;
}
int EpollServer::OnRead(Connection * c)
{
char buf[4096] = {0};
int toread = 0;
while (1)
{
memset(buf, 0, sizeof(buf));
int bytes = recv(c->fd, buf, 4095, 0);
if (bytes < 0)
{
if (errno == EINTR)
{
continue;
}
else if (errno == EAGAIN)
{
break;
}
else
{
return -1;
}
}
else if (bytes == 0)
{
OnClose(c);
break;
}
else
{
c->recvBuffer.append(buf, bytes);
}
}// end while
if (!c->recvBuffer.empty())
{
OnResponse(c);
c->recvBuffer.clear();
}
return 0;
}
int EpollServer::OnWrite(Connection * c)
{
if (c->sendBuffer.empty())
{
c->writeReady = 1;
printf("write ready, %d\n", c->fd);
}
else
{
int pos = 0;
int towrite = c->sendBuffer.length();
const char* buf = c->sendBuffer.c_str();
do
{
int bytes = send(c->fd, buf+pos, towrite, 0);
if (bytes < 0)
{
if (errno == EINTR)
{
continue;
}
else if (errno == EAGAIN)
{
break;
}
else
{
return -1;
}
}
else if (bytes == 0)
{
OnClose(c);
}
else
{
pos += bytes;
towrite -= bytes;
}
}while (towrite > 0);
if (pos > 0)
{
printf("send bytes: %d\n", pos);
pthread_mutex_lock(&c->mutex);
c->sendBuffer.erase(0, pos);
pthread_mutex_unlock(&c->mutex);
}
}
return 0;
}
int EpollServer::PostSend(Connection *c)
{
if (c->writeReady)
{
int pos = 0;
int towrite = c->sendBuffer.length();
const char* buf = c->sendBuffer.c_str();
do
{
int bytes = send(c->fd, buf+pos, towrite, 0);
if (bytes < 0)
{
if (errno == EINTR)
{
continue;
}
else if (errno == EAGAIN)
{
break;
}
else
{
return -1;
}
}
else if (bytes == 0)
{
OnClose(c);
}
else
{
pos += bytes;
towrite -= bytes;
}
}while (towrite > 0);
if (pos > 0)
{
printf("send bytes: %d\n", pos);
pthread_mutex_lock(&c->mutex);
c->sendBuffer.erase(0, pos);
pthread_mutex_unlock(&c->mutex);
}
}
else
{
c->writeReady = 0;
printf("post send not ready\n");
}
return 0;
}
bool EpollServer::Start(void)
{
stop = false;
if (0 != pthread_create(&thread, 0, WorkProcProxy, this))
{
printf("create thread failed, %s\n", strerror(errno));
return false;
}
return true;
}
void EpollServer::Stop(void)
{
stop = true;
pthread_join(thread, 0);
}
}
epoll的设计与实现
最新推荐文章于 2024-04-18 18:00:55 发布