网狐棋牌框架-WHDataQueue队列的问题

研究网狐的内核框架发现经常有以下错误:

SocketEngine Index=0,RountID=18,OnRecvCompleted 发生“数据包效验码错误”异常

 

因为不是必现的问题,非常不好排查,而网狐的东西也相对较稳定,不知如何下手,然后就仔细看内核相关的代码,看到了内存数据队列;WHDataQueue队列的实现其实还是非常巧妙的,用变量标志就在一个内存块上实现了环形的队列,越是巧妙的东西,就越容易出错,也就越需要打磨,虽然研究网狐框架代码的人很多,但不知道为什么我在网上各种找资料,就是找不到这个问题的解决方案,可能这是个偶发的问题,在服务端跑的时候,也极少出现,就算出现也只是影响某个玩家,所以问题就被隐藏了吧。

 

 

         int nIndex = 0;
        TCHAR szInfo[4096] = TEXT("");
        int nLen = 0;
         
        //写入0字节, 让gDataQueue内存块大小为 40, 实际上是写入4字节,因为里面还有个数据头
        rand_str(szInfo, 0); 
        gDataQueue.InsertData(++nIndex, szInfo, 0);
        tagDataHead head;
        //取出,之后 m_dwDataQueryPos 变成4
        gDataQueue.DistillData(head, szInfo, sizeof(szInfo)); 
 
        //写入16个字节
        rand_str(szInfo, 7); 
        nLen = CountStringBuffer(szInfo); 
        gDataQueue.InsertData(++nIndex, szInfo, nLen);
        std::cout << nLen <<", " << nIndex << endl;
 
        //取出,之后 m_dwDataQueryPos 变成24, m_dwDataSize=0
        gDataQueue.DistillData(head, szInfo, sizeof(szInfo));
        std::cout << head.wDataSize << ", " << head.wIdentifier<< endl; 
 
        std::cout << "" << endl;
 
        //写入20字节, 
        //因为写入到结束位置,写入位置+写入长度大于总长,查询位置大于写入长度,
        //基于以上三点原因,说明可以写从头开始再入,所以会把 m_dwInsertPos 设置为0
        rand_str(szInfo, 9); 
        nLen = CountStringBuffer(szInfo);
        gDataQueue.InsertData(++nIndex, szInfo, nLen);
        std::cout << nLen << ", " << nIndex << endl;
 
        //再写入10字节
        rand_str(szInfo, 3);
        nLen = CountStringBuffer(szInfo);
        //写入10字节之后, 
        //实际上gDataQueue就变成m_dwDataQueryPos = 24(因为没有读取操作)
        //m_dwDataSize = 38, m_dwInsertPos = 38
        //到这一步貌似也还没有问题,但是如果后续的操作不是读取而是继续写入,那么就有出现问题
        gDataQueue.InsertData(++nIndex, szInfo, nLen);
        std::cout << nLen << ", " << nIndex << endl;
 
        rand_str(szInfo, 28);
        nLen = CountStringBuffer(szInfo);
        //为了测试问题,这一步继续写入,因为总长是40,再写入,则会重新分配空间
        //重新分配空间时,需要将原有内存数据拷贝到新内存,问题就出现这个拷贝上,步骤如下:
        //1. 判断是否存在末尾还有未读完的数据:m_dwTerminalPos-m_dwDataQueryPos=14
        //2. 先将末尾数据拷贝:CopyMemory(pNewQueueServiceBuffer, m_pDataQueueBuffer + m_dwDataQueryPos, dwPartOneSize);
        //3. 再从头开始拷贝:CopyMemory(pNewQueueServiceBuffer + dwPartOneSize, m_pDataQueueBuffer, m_dwInsertPos);
        //这个步骤理论上是没有错的,但是结合上面的写入数据的顺序,则忽略了一个细节: 写入的数据长度已经覆盖了查询标记
        gDataQueue.InsertData(++nIndex, szInfo, nLen);
        std::cout << nLen << ", " << nIndex << endl;
 
        std::cout << "" << endl;
 
        gDataQueue.DistillData(head, szInfo, sizeof(szInfo));
        std::cout << head.wDataSize << ", " << head.wIdentifier << endl;
        gDataQueue.DistillData(head, szInfo, sizeof(szInfo));
        std::cout << head.wDataSize << ", " << head.wIdentifier << endl;
        gDataQueue.DistillData(head, szInfo, sizeof(szInfo)); 
        std::cout << head.wDataSize << ", " << head.wIdentifier << endl;

 

 

修复代码:

在bool CWHDataQueue::RectifyBuffer(DWORD dwNeedSize)函数中加上一行:

 

     try
    {
        //缓冲判断
        if ((m_dwDataSize+dwNeedSize)>m_dwBufferSize) throw 0;
 
        //重新开始
        if ((m_dwInsertPos==m_dwTerminalPos)&&((m_dwInsertPos+dwNeedSize)>m_dwBufferSize)) 
        {
            if (m_dwDataQueryPos>=dwNeedSize) m_dwInsertPos=0;
            else throw 0;
        }
 
        //缓冲判断
        if ((m_dwInsertPos<m_dwTerminalPos)&&((m_dwInsertPos+dwNeedSize)>m_dwDataQueryPos)) throw 0;
 
        
        //头追上尾或尾追上头
        if (m_dwInsertPos + dwNeedSize > m_dwDataQueryPos && m_dwDataQueryPos >= m_dwInsertPos)
        {
            //尾追上头
            if (m_dwDataSize > 0) throw 0;
        }
        
    }


原文出处:https://blog.csdn.net/lzyuan1006/article/details/53389073?utm_source=itdadao&utm_medium=referral

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值