live555的任务调度是基于select的,其实select也不是很差,主要看使用场合,在并发量不是很大的时候效果还是很好的,而且很多平台都支持。当然,在Linux下有更好的选择,那就是epoll,将live555的任务调度改为epoll,能够进一步提高网络事件的处理能力,我在 BasicTaskScheduler 下添加了对epoll的支持,并没有删除select的实现,这样可以同时在windows和linux下编译使用。下面贴出主要部分,后面会给出代码的下载地址。 SingleStep 修改:
1 void BasicTaskScheduler::SingleStep(unsigned maxDelayTime)
2 {
3 // ....
4 unsigned timeout = tv_timeToDelay.tv_sec*1000+(tv_timeToDelay.tv_usec/1000);
5 struct epoll_event events[1] = {0};
6
7 int numEvent = epoll_wait(_epollfd, events, 1, timeout);
8 if(numEvent < 0)
9 {
10 if (errno != EINTR)
11 internalError();
12 }
13 else
14 {
15 HandlerDescriptor* handler = NULL;
16 int conditionSet = 0;
17 for(int i=0; i<numEvent; i++)
18 {
19 if(events[i].data.ptr == NULL)
20 continue;
21 handler = (HandlerDescriptor*)(events[i].data.ptr);
22 conditionSet = 0;
23 if(events[i].events & EPOLLIN)
24 conditionSet |= SOCKET_READABLE;
25 if(events[i].events & EPOLLOUT)
26 conditionSet |= SOCKET_WRITABLE;
27 if(events[i].events&EPOLLERR || events[i].events&EPOLLPRI)
28 conditionSet |= SOCKET_EXCEPTION;
29
30 if ((conditionSet&handler->conditionSet) != 0
31 && handler->handlerProc != NULL )
32 {
33 fLastHandledSocketNum = handler->socketNum;
34 (*handler->handlerProc)(handler->clientData, conditionSet);
35 }
36 }
37 }
38
39 // ....
40 } setBackgroundHandling 修改:
void BasicTaskScheduler
::setBackgroundHandling(int socketNum, int conditionSet, BackgroundHandlerProc* handlerProc, void* clientData)
{
// ...
HandlerIterator iter(*fHandlers);
HandlerDescriptor* handler = NULL;
while ((handler = iter.next()) != NULL) // lookupHandler
{
if (handler->socketNum == socketNum)
break;
}
struct epoll_event event = {0};
event.data.ptr = handler;
if (conditionSet&SOCKET_READABLE)
event.events |= EPOLLIN;
if (conditionSet&SOCKET_WRITABLE)
event.events |= EPOLLOUT;
if (conditionSet&SOCKET_EXCEPTION)
event.events |= (EPOLLPRI|EPOLLERR);
if(epoll_ctl(_epollfd, EPOLL_CTL_ADD, socketNum, &event) < 0)
{
if(errno == EEXIST)
epoll_ctl(_epollfd, EPOLL_CTL_MOD, socketNum, &event);
}
// ...
} moveSocketHandling 修改:
void BasicTaskScheduler::moveSocketHandling(int oldSocketNum, int newSocketNum)
{
// ...
HandlerIterator iter(*fHandlers);
HandlerDescriptor* handler = NULL;
while ((handler = iter.next()) != NULL) // lookupHandler
{
if (handler->socketNum == oldSocketNum)
break;
}
if(!handler)
return ;
struct epoll_event event = {0};
event.data.ptr = handler;
if(handler->conditionSet&SOCKET_READABLE)
event.events |= EPOLLIN;
if(handler->conditionSet&SOCKET_WRITABLE)
event.events |= EPOLLOUT;
if(handler->conditionSet&SOCKET_EXCEPTION)
event.events |= (EPOLLPRI|EPOLLERR);
if(event.events != 0)
{
epoll_ctl(_epollfd, EPOLL_CTL_DEL, oldSocketNum, NULL);
epoll_ctl(_epollfd, EPOLL_CTL_ADD, newSocketNum, &event);
}
#if defined(__linux) || defined(__linux__)
struct epoll_event event = {0};
event.data.ptr = handler;
if(handler->conditionSet&SOCKET_READABLE)
event.events |= EPOLLIN;
if(handler->conditionSet&SOCKET_WRITABLE)
event.events |= EPOLLOUT;
if(handler->conditionSet&SOCKET_EXCEPTION)
event.events |= (EPOLLPRI|EPOLLERR);
if(event.events != 0)
{
epoll_ctl(_epollfd, EPOLL_CTL_DEL, oldSocketNum, NULL);
epoll_ctl(_epollfd, EPOLL_CTL_ADD, newSocketNum, &event);
}
#else
// ...
#endif
// ...
} epoll的主要实现就是这些,我在windows和linux下编译通过,做了简单的测试,如果有什么疑问可以提出。后续我会给出live555多线程的实现。 我把代码放在了github,希望对你有帮助 ^_^ 代码: https://github.com/PHZ76/live555_epoll
|