核心代码如下
m_bRunning = true;
// first let's increase the limit of open files
int maxconn = 100000;
struct rlimit srl;
srl.rlim_cur = maxconn + 10;
srl.rlim_max = maxconn + 10;
if (setrlimit(RLIMIT_NOFILE, &srl) < 0)
{
LOG4CXX_FATAL(logger_, "Cannot set RLimit!");
exit(1);
}
epfd = epoll_create(maxconn);
if (epfd < 0)
{
LOG4CXX_FATAL(logger_, "epoll_create error!");
exit(1);
}
// Now let's ignore broken pipes
struct sigaction sa;
memset(&sa, 0, sizeof (sa));
sa.sa_handler = SIG_IGN;
if (sigaction(SIGPIPE, &sa, NULL) < 0)
{
LOG4CXX_WARN(logger_, "Error ignoring SIGPIPE!");
}
if (initSockets() < 0)
{
exit(1);
}
struct epoll_event ev, evs[MAX_EVENTS];
LOG4CXX_INFO(logger_, "Nethandler started.");
for (; ; )
{
if (!m_bRunning)
{
break;
}
int count = epoll_wait(epfd, evs, MAX_EVENTS, 10);
if (count < 0)
{
LOG4CXX_FATAL(logger_, "epoll_wait error!");
}
time_t now = Clock::getCurrentSystemTime();
if (!preNetEvent(now))
{
LOG4CXX_ERROR(logger_, "PreNetEvent returned false, terminating...");
break;
}
for (int i = 0; i < count; i++)
{
int fd = evs[i].data.fd;
if (isListenSocket(fd))//如果是监听描述符
{
struct sockaddr_in sa;
socklen_t slen = sizeof (sa);
int nfd = 0;
nfd = accept(fd, (struct sockaddr*) &sa, &slen);
if (nfd > 0)
{
//向events中添加新增的文件描述符
ev.events = EPOLLIN | EPOLLHUP; //| EPOLLRDHUP;
ev.data.fd = nfd;
if (epoll_ctl(epfd, EPOLL_CTL_ADD, nfd, &ev) < 0)
{
LOG4CXX_ERROR(logger_, "epoll_ctl error, cannot add client!");
}
else
{
size_t rsize = readCacheSize(fd);
//size_t rsize = (fd==wsfd ? NetCache::WEBSERVER_READ_SIZE : NetCache::DEFAULT_READ_SIZE);
NetCache *cache = addConnection(nfd, sa, rsize);//添加新的NetCache
createProtocolHandler(cache, fd);//设置NetCache类型
}
}
}
else // data
{
NetCache *cache = getCacheFromFd(fd);
if (cache != NULL)
{
__uint32_t events = evs[i].events;
bool readError = false;
if ((events & EPOLLIN) > 0)//如果是可写事件
{
int64 uid = cache->uid;
readError = !cache->read();//读数据并且放入自定义读缓存中
if (!readError)
{
string req;
while (cache->assemble(req) && !cache->remove)
{
//LOG4CXX_DEBUG(logger_, "Command Received: \"" << req.c_str() << "\" from uid:" << uid << " fd:" << fd);
if (cache->ph != NULL)
{
cache->ph->handle(uid, req);
}
else
{
LOG4CXX_ERROR(logger_, "Protocol handler is NULL for fd:" << fd);
}
}
}
}
if ((events & EPOLLOUT) > 0)//可写事件
{
if ( isConnecting( fd ))
{
connectSuccess( fd );
}
else if (cache->write())
{
ev.events = EPOLLIN | EPOLLHUP; // | EPOLLRDHUP;
ev.data.fd = fd;
epoll_ctl(epfd, EPOLL_CTL_MOD, fd, &ev);
}
}
if ((cache->remove && !cache->waitToWrite()) || readError ||
(events & EPOLLHUP) > 0 || //(events&EPOLLRDHUP)>0 ||
(events & EPOLLERR) > 0)
{
int64 uid = cache->uid;
if (uid >= 0 && cache->ph != NULL)
{
cache->ph->leave(uid);
}
LOG4CXX_DEBUG(logger_, "Client disconnected of fd:" << fd
<< ", remove: " << cache->remove << ", read error: "
<< readError << ", hup: " << (events & EPOLLHUP)
//<< //", rdhup: " << (events & EPOLLRDHUP)
<< ", epoll error: " << (events & EPOLLERR));
doCloseConnection(fd);
if (isConnectSocket(fd))
{
connectFailed(fd);
}
}
}
else
{
LOG4CXX_ERROR(logger_, "Cannot find cache for fd:" << fd);
}
}
}
}