本模块用来处理客户连接上接收(发送)到的数据。
当监听的文件描述符触发EPOLLIN时,将客户连接加入请求队列中,线程竞争来处理该连接。线程判断是读数据还是写数据,调用处理函数.
线程按照两种处理模式处理:
reactor模式中,主线程(I/O处理单元)只负责监听文件描述符上是否有事件发生,
有的话立即通知工作线程(逻辑单元 ),读写数据、接受新连接及处理客户请求均在工作线程中完成。通常由同步I/O实现。
proactor模式中,主线程和内核负责处理读写数据、接受新连接等I/O操作,工作线程仅负责业务逻辑,
如处理客户请求。通常由异步I/O实现。
线程的处理模式 reactor proactor
主线程
处理用户发送的数据
util_timer *timer = users_timer[sockfd].timer;//从定时链表中获得连接的定时器
if (1 == m_actormodel)
{
if (timer)
{
adjust_timer(timer);//更新连接的活动时间
}
//若监测到读事件,将该事件放入请求队列 将http数组的第sockfd加入线程池中
m_pool->append(users + sockfd, 0);
while (true)
{
if (1 == users[sockfd].improv)
//当线程处理过时,improv等于1 request->improv = 1;
{
if (1 == users[sockfd].timer_flag)//timer_flag为结束连接
{
deal_timer(timer, sockfd);
users[sockfd].timer_flag = 0;
}
users[sockfd].improv = 0;
break;
}
}
}
else
{
//proactor
if (users[sockfd].read_once())//有数据可读
{
LOG_INFO("deal with the client(%s)", inet_ntoa(users[sockfd].get_address()->sin_addr));
//若监测到读事件,将该事件放入请求队列
m_pool->append_p(users + sockfd);
if (timer)
{
adjust_timer(timer);
}
}
else
{
deal_timer(timer, sockfd); //无数据可读则直接删除
}
}
发送给用户数据
if (1 == m_actormodel)
{
if (timer)
{
adjust_timer(timer);
}
m_pool->append(users + sockfd, 1);
while (true)
{
if (1 == users[sockfd].improv)//线程处理过的标志 improv为1
{
if (1 == users[sockfd].timer_flag)//当线程发现无数据处理时,将timer_flag设为1
{
deal_timer(timer, sockfd);
users[sockfd].timer_flag = 0;
}
users[sockfd].improv = 0; //代表该线程已经处理过
break;
}
}
}
else
{
//proactor
if (users[sockfd].write())
{
LOG_INFO("send data to the client(%s)", inet_ntoa(users[sockfd].get_address()->sin_addr));
if (timer)
{
adjust_timer(timer);
}
}
else
{
deal_timer(timer, sockfd);
}
}
工作线程
if (1 == m_actor_model) // 1为reactor
{
if (0 == request->m_state) //0为读 1为写
{
if (request->read_once()) //当连接中有数据可读时
{
request->improv = 1;
connectionRAII mysqlcon(&request->mysql, m_connPool);
//获得http内的数据库连接
request->process(); //处理数据
}
else//无数据可以直接删除
{
request->improv = 1;
request->timer_flag = 1;
}
}
else
{
if (request->write())// 是否可以写
{
request->improv = 1;
}
else //无数据可以直接删除
{
request->improv = 1;
request->timer_flag = 1;
}
}
}
else //为proactor
{
connectionRAII mysqlcon(&request->mysql, m_connPool);
request->process(); //将m_socketfd改为EPOLLIN
}
线程获得客户连接读取数据:
bool http_conn::read_once()//读取数据
{
if (m_read_idx >= READ_BUFFER_SIZE)
{
return false;
}
int bytes_read = 0;
//LT读取数据
if (0 == m_TRIGMode)
{
bytes_read = recv(m_sockfd, m_read_buf + m_read_idx, READ_BUFFER_SIZE - m_read_idx, 0);//从套接字接收数据,存储在m_read_buf缓冲区
m_read_idx += bytes_read;
if (bytes_read <= 0)//小于等于则出错或者无数据
{
return false;
}
return true;
}
//ET读数据 ET触发次数少 保证少次读完用循环
else
{
while (true)
{
bytes_read = recv(m_sockfd, m_read_buf + m_read_idx,