本文将介绍我曾经做过的一个项目的服务器架构和服务器编程的一些重要细节。
一、程序运行环境
操作系统:centos 7.0
编译器:gcc/g++ 4.8.3 cmake 2.8.11
mysql数据库:5.5.47
项目代码管理工具:VS2013
一、程序结构
该程序总共有17个线程,其中分为9个数据库工作线程D和一个日志线程L,6个普通工作线程W,一个主线程M。(以下会用这些字母来代指这些线程)
(一)、数据库工作线程的用途
9个数据库工作线程在线程启动之初,与mysql建立连接,也就是说每个线程都与mysql保持一路连接,共9个数据库连接。
每个数据库工作线程同时存在两个任务队列,第一个队列A存放需要执行数据库增删查改操作的任务sqlTask,第二个队列B存放sqlTask执行完成后的结果。sqlTask执行完成后立即放入结果队列中,因而结果队列中任务也是一个个的需要执行的任务。大致伪代码如下:
void db_thread_func()
{
while (!m_bExit)
{
if (NULL != (pTask = m_sqlTask.Pop()))
{
//从m_sqlTask中取出的任务先执行完成后,pTask将携带结果数据
pTask->Execute();
//得到结果后,立刻将该任务放入结果任务队列
m_resultTask.Push(pTask);
continue;
}
sleep(1000);
}
}
现在的问题来了:
1. 任务队列A中的任务从何而来,目前只有消费者,没有生产者,那么生产者是谁?
2. 任务队列B中的任务将去何方,目前只有生产者没有消费者。
这两个问题先放一会儿,等到后面我再来回答。
(二)工作线程和主线程
在介绍主线程和工作线程具体做什么时,我们介绍下服务器编程中常常抽象出来的几个概念(这里以tcp连接为例):
1. TcpServer 即Tcp服务,服务器需要绑定ip地址和端口号,并在该端口号上侦听客户端的连接(往往由一个成员变量TcpListener来管理侦听细节)。所以一个TcpServer要做的就是这些工作。除此之外,每当有新连接到来时,TcpServer需要接收新连接,当多个新连接存在时,TcpServer需要有条不紊地管理这些连接:连接的建立、断开等,即产生和管理下文中说的TcpConnection对象。
2.一个连接对应一个TcpConnection对象,TcpConnection对象管理着这个连接的一些信息:如连接状态、本端和对端的ip地址和端口号等。
3.数据通道对象Channel,Channel记录了socket的句柄,因而是一个连接上执行数据收发的真正执行者,Channel对象一般作为TcpConnection的成员变量。
4. TcpSession对象,是将Channel收取的数据进行解包,或者对准备好的数据进行装包,并传给Channel发送。
归纳起来:一个TcpServer依靠TcpListener对新连接的侦听和处理,依靠TcpConnection对象对连接上的数据进行管理,TcpConnection实际依靠Channel对数据进行收发,依靠TcpSession对数据进行装包和解包。也就是说一个TcpServer存在一个