用环形缓冲实现拼包函数

大家都知道,网络tcp,流socket是不能保证收到的包是逻辑完整的,也许一个逻辑完整的被分成两段发送,所以我们使用流socket就需要将接收的包(物理包),经过整理变成逻辑包。然后再处理。这个整理包的函数就是所说的拼包函数。下面的代码用环形缓冲实现了一个拼包函数。环形缓冲可以减少不必要memcpy,从而提高效率。

// 这是per-I/O数据。它包含了在套节字上处理I/O操作的必要信息
struct TPerIoData
{
 OVERLAPPED ol;                      //重叠io,必须为第一个数据
 WSABUF     dataBuf;                 //投递数据时的结构
char       buff[IO_BUF_LEN];        //接收或发送的io数据的buffer
int        bufferLen;               //buffer长度
 SOCKET     sClient;                 // 在Accept一个连接后,通过它传递连接的客户端
int        opType;                  // 操作类型:Operation_type
};

// 这是per-Handle数据。它包含了一个套节字的信息
struct TIOCPContext
{
 SOCKET s;              // 套节字句柄
 SOCKADDR_IN addrRemote;   // 连接的远程地址
 BOOL bClosing;         // 套节字是否关闭
int nPostNum;             // 此套节字上抛出的重叠操作的数量
 BYTE* lpBufBegin;           //拼包缓冲区头指针
  BYTE* lpBufEnd;             //拼包缓冲区尾指针
int arrayDataLen;           //拼包缓冲目前长度
  BYTE arrayDataBuf[USE_DATA_LONGTH]; //拼包缓冲区
 CRITICAL_SECTION Lock;   // 保护这个结构
};

bool CUserServer::SplitPacket(TIOCPContext *pContext, TPerIoData *pBuffer, char* outBuf)
{
int recvedCount = pBuffer->bufferLen; //收到的数据长度
//守卫pContext结构
 CGuardLock(&pContext->Lock);
//如果缓冲区不够,说明包格式有问题,则丢弃数据
if(USE_DATA_LONGTH - pContext->arrayDataLen < recvedCount)
    {
  pContext->lpBufBegin = pContext->lpBufEnd = pContext->arrayDataBuf;
    pContext->arrayDataLen = 0;
return false;
 }

int lastLen;
//将接收的数据copy到整理缓冲区
if(pContext->lpBufEnd <= pContext->lpBufBegin) //假如尾指针在头指针前面
 {
  memcpy(pContext->lpBufEnd, pBuffer->buff, recvedCount);
 }
else
 {
  lastLen  = USE_DATA_LONGTH - (pContext->lpBufEnd - pContext-  >arrayDataBuf); //尾指针到缓冲最后位置的大小
if(lastLen < recvedCount) //不能完全copy到最后
 {
   memcpy(pContext->lpBufEnd, pBuffer->buff, lastLen);
   memcpy(pContext->arrayDataBuf, pBuffer-    >buff + lastLen, recvedCount - lastLen);

  }
else
{
   memcpy(pContext->lpBufEnd, pBuffer->buff, recvedCount);
  }
 }
//更新尾指针
if(lastLen <= recvedCount)
{
  pContext->lpBufEnd = pContext->arrayDataBuf + recvedCount - lastLen;
 }
else
{
  pContext->lpBufEnd += recvedCount;
 }
//更新缓冲长度
 pContext->arrayDataLen += recvedCount;

//根据包格式判断包是否完整,包格式 = type(4byte) + packetlen(4byte) + content
if(pContext->arrayDataLen < 8) //收到的包不完整

//返回,等下次再整理
return false;
 }

 char tmpBuf[10] = {'/0'};
 lastLen = USE_DATA_LONGTH - (pContext->lpBufBegin - pContext->arrayDataBuf); //头指针到整理缓冲末尾的大小
 if(lastLen < 8)
 {
  memcpy(tmpBuf, pContext->lpBufBegin, lastLen);
  memcpy(tmpBuf + lastLen, pContext->arrayDataBuf, 8 - lastLen);
 }
 else
 {
  memcpy(tmpBuf, pContext->lpBufBegin, 8);
 }
 //得到包长度
 int packLen = atoi(tmpBuf + 4);
 if(packLen > MAX_PACKET_LEN || packLen < 0 )
 {
  //包长度有问题,则丢弃现在缓冲中的消息
  pContext->lpBufBegin = pContext->lpBufEnd = NULL;
  pContext->arrayDataLen = 0;
  return false;
 }
 if(packLen > pContext->arrayDataLen - 8)
 {
  //包还不完整,等下次再整理
  return false;
 }
 //现在将逻辑完整的包copy到out参数中去
 if(lastLen < 8 + packLen)
 {
  memcpy(outBuf, pContext->lpBufBegin, lastLen);
  memcpy(outBuf + lastLen, pContext->arrayDataBuf, 8 + packLen - lastLen);
 }
 else
 {
  memcpy(tmpBuf, pContext->lpBufBegin, 8 + packLen);
 }
 //更新头指针
 if(lastLen <= 8 + packLen)
 {
  pContext->lpBufBegin = pContext->arrayDataBuf + 8 + packLen - lastLen;
 }
 else
 {
  pContext->lpBufBegin += (8 + packLen);
 }
 //更新长度
 pContext->arrayDataLen -= 8 + packLen;
 return true;

}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值