RDT的切包和组包
更新日期:2025/2/13
概述
RDTAPIs是P2P sdk里面的一个提供可靠传输的模块,提供通用的数据传输(read和write)接口,发送端和接收端都有缓存区用以缓存发送中或者接收中的数据。
因为RDT模块在发送数据时,不会完全按照一帧一帧地传,实际为可能一帧被分成多个分片,或者多帧组成一个分片来传,所以接收端在读取数据的时候,需要对数据进行重组。
RDT的帧设计
RDT的一帧可以设计为5个部分,分别为帧起始标志,帧类型,当前帧大小,帧数据,帧结束位:
frmBegin[4] |frmInfo[5] | data[...] | frmEnd[2]
设计帧头frmInfo为:type+dataSize
type[1] | dataSize[4]
开发者可以根据实际场景,修改frmInfo,只要确保两端使用同样的frmInfo即可。
RDT的帧读取方法
- RDT帧的读取原则:
- 先读取frmBegin,4个字节。
- 接着读取一个frmInfo,5个字节。
- 从frmInfo中解析出type以及dataSize,然后进行数据读取:
读取数据头:
int readFrameInfo(char* frmInfo,size_t frmInfoBufferSize,int frmInfoSize){ int readSize = 0; int rest = frmInfoSize; memset(frmeInfo,0,frmInfoBufferSize); while(rest > 0){ readSize = RDT_Read(rdt_channel_id,frmInfo+frmInfoSize-rest,rest,1000); if(readSize == RDT_ER_TIMEOUT){ continue; } else if(readSize < 0){ return readSize; } rest -= readSize; } return 0; }
读取数据:
//读取帧数据,确保buffer足够大,否则进行resize buffer。
int readOneFrame(char* dataBuf,size_t dataBufferSize,int dataSize){ int readSize = 0; int rest = dataSize; memset(dataBuf,0,dataBufferSize); while(rest > 0){ readSize = RDT_Read(rdt_channel_id,dataBuf+dataSize-rest,rest,1000); if(readSize == RDT_ER_TIMEOUT){ continue; } else if(readSize < 0){ break; } rest -= readSize; } }
读取帧结束标志:
int readFrameEndFlag(){ int readSize = 0; int rest = 2; char buffer[8] = {0}; while(rest > 0){ readSize = RDT_Read(rdt_channel_id,buffer+2-rest,rest,1000); if(readSize == RDT_ER_TIMEOUT){ continue; } else if(readSize < 0){ return readSize; } rest -= readSize; } return 0; }
所以循环读取一个完整帧的方法:
#define FRAME_INFO_SIZE 5 ... while(1){ char frmInfoBuffer[8]={0}; if(readFrameInfo(frmInfoBuffer,8,FRAME_INFO_SIZE) < 0){ break; } //分析frmInfo,得到type,dataSize。 parseFrameInfo(frmInfo,type,dataSize); char dataBuffer[100*1024]={0}; if(readOneFrame(dataBuffer,100*1024,dataSize) < 0){ break; } //已读取完整地一帧数据 handleUserData(dataBuf); if(readFrameEndFlag() < 0){ break; } }
到此为止,已经完成了对RDT数据的解析,开发者可以在开发过程中,根据项目的实际情况,设计自己的帧格式。