服务器开发之 IO 处理

  服务器的主要事务是处理各种逻辑,为上千上万的用户提供特定的服务。所以,对它的要有能够应对高并发的特点,同时还要有高的响应处理能力,稳定性更是不用多说,这是第一位的,没有玩家希望自己购买的道具丢失。
              下面花一个简单的服务器进程的模型图,说明服务器进程的基本事务结构,其实就是和一些他要处理的 IO 的关系。



              上面的图中,服务器进程中一共接入了三个IO处理模块,其中两个是网络IO,一个是数据库IO, 还有一中可能就是服务器还会接入本地文件IO, 写log,加载配置等操作。 但基本就是些IO类型。
              简单说明一下:
              IO(A)负责处理客户端的接入。
              IO(B)负责和别的服务器进行通信,交换数据。
              IO(C)负责加载和保存数据。

             下面说说这些IO特点,这些io的共同特点都是比较慢的,并且他们的操作都是会阻塞的,最快的也应该是0.001秒的数量级别,这也许在我们看来是很快了,如果每个处理都是0.001秒,那么一秒钟也就处理1000个,这个速度对服务器来说还是太慢,所以我们要这些io的操作放到独立的工作线程里面去处理他们的io读和写操作,逻辑放入到主逻辑线程D里面去操作。因为逻辑需要牵涉到方方面面的数据和操作,如果直接在线程里面处理是需要很多的线程安全机制来保证安全,这样会给逻辑开发带来工作量,也给调试带来困难。这就是我想说的,我们应该如何处理这些io数据。这个时候你心里肯定也知道,我弄个线程安全的队列来交换数据。呵呵,是的你想的很多,大的理论就是这样干的,我想说一些细节上面的东西。



         struct  TDataBlock
         {
                    index;                                //数据库编号
                    enter_time;                       //进入队列的时间
                    live_maxtime;                    //最多生命时间
                  
                    //
                    yourdatabufer;                 //你自己的数据信息
          }

数据处理的大概流程,



        这里的核心部件是A,B,他们是线程安全的队列。这样可以保障两个线程之间的同步关系,同时保证数据的安全。下面是其实现的大概代码,删除了一些细节上的实现。


//一个现场安全的队列
template<typename A>
class XThreadSaveQueue
{
    typedef std::list<A> IN_QUEUE;
public:
    XThreadSaveQueue(){    }
    ~XThreadSaveQueue(){}

    void push(const A _Val)
    {
        CXXLocker lock();
        m_q.push_back( _Val );
    }
    void push_front(const A _Val)
    {
        CXXLocker lock();
        m_q.push_front( _Val );
    }

    A pop( bool &isok )
    {
        CXXLocker lock();
        isok = false;
        if( m_q.empty() )
            return A();
        isok = true;
        A item = m_q.front();
        m_q.pop_front();
        return item;
    }
    A& front()
    {
        CXXLocker lock();
        return m_q.front();
    }

    unsigned int size()
    {
        CXXLocker lock();
        return m_q.size();
    }
    bool empty()
    {
        CXXLocker lock();
        return m_q.empty();
    }
private:
    IN_QUEUE  m_q;
};

typedef XThreadSaveQueue<TDataBlock*> QueueData;

class CYourWorkThread:public CThread
{
public:
    CYourWorkThread();
    virtual ~CYourWorkThread(void);

public:
    void  push_req( TDataBlock *pData ){ m_req_queue.push(pData); }

    //这个函数工作在主逻辑线程里面
    void  app_run()
    {
        //处理rep返回的数据
    }
protected:
    //这个函数工作在子线程里面
    void  ThreadRun(void)
    {
        //处理req的请求队列
    }

private:
    QueueData    m_req_queue;    //我自己需要处理的请求队列
    QueueData    m_rep_queue;    //我自己需要处理的请求队列

};



注意:
        1: 必须注意 app_run(), ThreadRun(),这个两个函数里面的异常处理,保证队列的正常进入和删除,否则会有内存泄漏,或者造成线程死循环,永远在处理一个数据块,而这个数据块也一直在发生异常。
       2: ThreadRun(void)上面的函数如果是子线程可以直接完成的工作,比如本地文件,数据库等操作,也就是说是同步完成的,是不要什么额外的处理工作的。 如果是异步的处理方式,比如网络。你需要添加一个map来保存正在处理的数据块,并且定时的检查他们得儿完成情况,并且做容错处理,这样一方面保证内存的安全,同时也保证客户端不会死等在一个界面里面。同时也降低客户端的冗余工作量。当然了一个好的客户端还是要有超时处理的。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值