天上午很不幸碰到一个select的问题,幸好以前对网络I/O处理的模块进行了封装,今天下午很快就完成了一个基于poll的I/O处理封装,
只需要进行1行代码的替换,就可以轻松从select架构转换到poll,同理也可以转换到epoll。
自己可以随心所欲的切换网络I/O处理架构!!!
这里是接口,使用的是模板,这里没有使用C++的继承,有如下几点考虑:
(1) 效率, 模板实现的多态是发生在编译的时候,而继承重载虚函数是通过程序运行的时候,根据vtable指针对函数的实际地址进行寻址,
当然比模板慢, 而且还可能会增加4字节的vptr指针
(2) 面向接口编程: 继承一般是有实际的逻辑含义的对象的使用,比如人,黑人之间。
而我们的网络处理模型,只是不同的处理方法,所以用模板更好一些
下面的代码请放到一个头文件中,不然存在编译问题,详情请见<<C++templates>>第6章
这里对fd的访问采用的是迭代模式,必须先启动开始迭代,让后才能依次迭代。
具体的网络模型对fd存放形式对于调用者是不可见的, 只能获取迭代指针,访问网络模型的内部fd列表。
各个实现类内存的数据结构自己是可以优化的,目前是全部采用数组
template <class T>
class InterfaceIOQuery
{
private:
class InterfaceIOQuery
{
private:
T member;
public:
//添加一个关心的fd
void remove(int* pFd, int iOption);
//测试该fd是否可读
bool isCanRead(int* pIterator);
//测试该fd是否可写
bool isCanWrite(int* pIterator);
//测试该fd是否异常
bool isExcept(int* pIterator);
//设置关心的事件
void setQueryOption(int iOption);
//注册一个fd
void registerFd(int pFd, int iOption);
void registerFd(int pFd, int iOption);
//轮询操作, -1 永久等待, 0轮询, >0, 按时间轮询
int selectWithTime(int iTime);
//开始遍历fd列表
int* getSelectFdBegin();
int* getSelectFdBegin();
//取得下一个fd的指针
int* getSelectFdNext();
};
具体的select
和poll, 接口的实现请见附件,
使用的范例代码如下:
//设置关心的事件
m_selector.setQueryOption(OP_READ);
//注册fd和该fd关心的事件
m_selector.registerFd(m_workPipeFd[0], OP_READ);
m_selector.registerFd(m_workPipeFd[0], OP_READ);
int iReady;
for ( ; ; )
{
{
//进行select操作
iReady = m_selector.selectWithTime(-1);
iReady = m_selector.selectWithTime(-1);
if (iReady < 0)
{
throw CException(errno);
}
else if (iReady == 0)
{
m_log.writeLog(LOG_INFO, "doSelect()", "work%d do select with 1 second time out", m_iThreadID);
}
else
{
{
throw CException(errno);
}
else if (iReady == 0)
{
m_log.writeLog(LOG_INFO, "doSelect()", "work%d do select with 1 second time out", m_iThreadID);
}
else
{
//开始迭代访问
m_selector.getSelectFdBegin();
m_selector.getSelectFdBegin();
int* iterator;
//为NULL标识访问完毕
while (NULL != (iterator = m_selector.getSelectFdNext()))
{
if (m_selector.isCanRead(iterator))
{
if (*iterator == m_workPipeFd[0])
{
int iRecive;
int iRead = r_read(*iterator, (void*)(&iRecive), sizeof(iRecive));
while (NULL != (iterator = m_selector.getSelectFdNext()))
{
if (m_selector.isCanRead(iterator))
{
if (*iterator == m_workPipeFd[0])
{
int iRecive;
int iRead = r_read(*iterator, (void*)(&iRecive), sizeof(iRecive));
if (iRead <= 0)
{
m_log.writeLog(LOG_ERR, "doSelect()", "work%d read pipe %d fail ", m_iThreadID, *iterator);
}
else
{
m_log.writeLog(LOG_INFO, "doSelect()", "work%d recevie fd %d success ", m_iThreadID, iRecive);
m_selector.registerFd(iRecive, OP_READ);
}
}
else
{
replayToClient(iterator);
}
--iReady;
{
m_log.writeLog(LOG_ERR, "doSelect()", "work%d read pipe %d fail ", m_iThreadID, *iterator);
}
else
{
m_log.writeLog(LOG_INFO, "doSelect()", "work%d recevie fd %d success ", m_iThreadID, iRecive);
m_selector.registerFd(iRecive, OP_READ);
}
}
else
{
replayToClient(iterator);
}
--iReady;
if (0 == iReady)
{
break;
}
}
}
}
}
{
break;
}
}
}
}
}