tcp 粘包 拆包解决思路以代码


pac.h

/**
* TCP拆包 粘包代码
* @author [email protected]
*/
#ifndef PAC_H
#define PAC_H
#ifndef INNER_BUFFER_SIZE
#define INNER_BUFFER_SIZE 10240         //内部缓冲区的大小
#endif
#include <memory.h>
#include <queue>
typedef unsigned char byte;
typedef struct _PAH_DESC{
    int length;
    int loop;
    byte* buffer;
} pac_desc;

//包队列(存放已经拆开的包)
static std::queue<pac_desc*> pendingQueue;
//内部缓冲区(分别多余包缓冲区以及当前处理缓冲区)
static pac_desc *pr=NULL,*pd=NULL;

//int转换为字节
static void int2byte(int i,byte* bytes,int size=4){
    memset(bytes,0,sizeof(byte)*size);
    bytes[0]=(unsigned char)(0xff&i);
    bytes[1]=(unsigned char)((0xff00&i)>>8);
    bytes[2]=(unsigned char)((0xff0000&i)>>16);
    bytes[3]=(unsigned char)((0xff000000&i)>>24);
}

//字节转换为int
static int byte2int(byte* bytes,int size=4){
    int addr=bytes[0]&0xFF;
    addr|=((bytes[1]<<8)&0xFF00);
    addr|=((bytes[2]<<16)&0xFF0000);
    addr|=((bytes[3]<<24)&0xFF000000);
    return addr;
}

/**
* 初始化
*/
void packet_init(){
}

//释放单个资源
void packet_recycle(pac_desc *pd){
    if(pd!=NULL){
        if(pd->buffer!=NULL){
            free(pd->buffer);
        }
        free(pd);
    }
}

/**
* 释放资源并销毁队列
*/
void packet_destory(){
     while(!pendingQueue.empty()){
        pac_desc* pt=(pac_desc*)pendingQueue.front();
        if(pt!=NULL){
            free(pt->buffer);
            free(pt);
        }
        pendingQueue.pop();
    }

    if(pr!=NULL){
        free(pr->buffer);
        free(pr);
        pr=NULL;
    }

    if(pd!=NULL){
        free(pd->buffer);
        free(pd);
        pd=NULL;
    }
}

//获取一个包
pac_desc* packet_out(){
    if(pendingQueue.empty()){
        return NULL;
    }
    pac_desc* pt=(pac_desc*)pendingQueue.front();
    pendingQueue.pop();
    return pt;
}

/**
* 获取队列大小
*/
int packet_size(){
    if(pendingQueue.empty()){
        return 0;
    }
    return pendingQueue.size();
}

/**
* 处理包长度和拆包,4字节:包内容
* buffer:内容指针
* size:指针长度
*/
void packet_in(byte* buffer,int size){
     if(pr!=NULL){
        if(pr->loop){
            //合并缓冲区,复制到缓冲区并指向新的缓冲区,大小为合并后的大小(内部缓冲区必须大于包的大小,仅分配一次内存)
            memcpy(pr->buffer+pr->loop,buffer,size);
            buffer=pr->buffer;
            size+=pr->loop;
            pr->loop=0;
        }
     }
     if(!size){
        return;
     }
     if(pd==NULL){
        pd=(pac_desc*)malloc(sizeof(pac_desc));
        pd->length=byte2int(buffer);
        pd->buffer=(byte*)malloc(pd->length);
        pd->loop=0;
        //调整指针和数据的长度
        buffer+=4;
        size-=4;
     }

     if(size>0){
         int cond=pd->loop+size;
         printf("%d\r\n",cond);
         if(cond>=pd->length){
            if(cond==pd->length){
                //刚好一个包
                memcpy(pd->buffer+pd->loop,buffer,size);
                pd->loop+=size;
                size=0;
            }else{
                //一个包后还有多余的
                int remain=(pd->length-pd->loop);
                memcpy(pd->buffer+pd->loop,buffer,remain);
                pd->loop+=remain;
                buffer+=remain;
                size-=remain;
            }
            if(pd->loop==pd->length){
                int pdh=pd->length;
                pendingQueue.push(pd);
                pd=NULL;
                if(size!=0){
                    //有多余的
                    if(size<4){
                        //不够包头的长度(需要启用第二缓冲区)
                        if(pr==NULL){
                            pr=(pac_desc*)malloc(sizeof(pac_desc));
                            //开启一块足够大的内存缓冲区
                            pr->buffer=(byte*)malloc(INNER_BUFFER_SIZE);
                        }
                        pr->length=size;
                        pr->loop=size;
                    }else{
                        packet_in(buffer,size);
                    }
                }
            }
         }else{
            memcpy(pd->buffer+pd->loop,buffer,size);
            pd->loop+=size;
         }
     }
}
#endif

test.cpp

#include <stdio.h>
#include <stdlib.h>
#include "pac.h"
typedef struct _TB{
    int length;
} TB;
int main(int argc,char* argv[]){
    TB tb={0};
    tb.length=1024;
    char buffer[1022];
    packet_in((byte*)&tb,sizeof(TB));
    packet_in((byte*)buffer,1020);
    packet_in((byte*)buffer,2);
    packet_in((byte*)buffer,2);
    packet_in((byte*)&tb,sizeof(TB));
    packet_in((byte*)buffer,1020);
    packet_in((byte*)buffer,2);
    pac_desc* pd=NULL;
    while((pd=packet_out())!=NULL){
        printf("packet:%d\t",pd->length);
    }
    packet_destory();
    return 0;
}
兴趣而已,业余时间学习学习,如有BUG海涵 偷笑


猜你喜欢

转载自blog.csdn.net/mak0000/article/details/80079482