一种通信接收缓冲区的操作想法

//////概述
在通信中,比如UART。接收到的数据经常是一帧一帧而不是一个字节一个字节,上层应用在需要读取通信数据的时候通常希望读取到的就是一个完整的帧,这样比较方便解析。如果底层对上层提供的接口是Read(port,buff,len,timeout)这种形式的话,上层为了避免收到的buff不是完整的一帧,len经常定得比较大,这样子的话就可能出现一种情况。假设底层接收到两帧,都放到缓冲区,上层这时调用读取接口,读到的不只是一帧,是一帧还多一些,这个时候去解析的话,就会把后面那一部分丢掉,那么下次再调底层接口读取数据的时候就会是剩下的那一半,肯定解析不了,必须丢掉。上面这种情况只会出现在发送方发送得比较快,接收方来不及接收的时候。如果是通信速度比较慢,接收方上层读取通信接口的速度比较快的话,就不会出现,因为根本不会出现缓冲区多于一帧的情况。实际上Linxu和Windows上的串口通信接口都是采用这种方式,所以如果通信速度快的话,都会出现丢帧的情况。下面这个程序就是为了解决这个问题,提出的一种想法。

实际通信中,串口通信都是有通信格式规定的,下面这个程序可以配合具体的通信协议做成传输层,构成  应用层--传输层--底层驱动  这种形式。
一种通信接收缓冲区的操作想法_第1张图片
一种通信接收缓冲区的操作想法_第2张图片
一种通信接收缓冲区的操作想法_第3张图片
一种通信接收缓冲区的操作想法_第4张图片




///////宏定义
#define TCPIPBUFFSIZE   200
typedef struct
{
    uint8 buff[TCPIPBUFFSIZE];
    uint16 Index;
    uint16 ReadIndex;
    uint8 BuffFull;
}ST_TCPREC;

/////////////////////////读缓冲区函数
ST_TCPREC TcpipRecBuff={0};
uint8 Client_TCP_Read(uint8* buff,uint16* len)
{
    uint8 tmp;
    

        if(TcpipRecBuff.BuffFull == 1 && (TcpipRecBuff.ReadIndex >= TcpipRecBuff.Index))
        {                                   //如果缓冲区满了,并且已经读完所以数据
            TcpipRecBuff.BuffFull=0;
            TcpipRecBuff.Index=0;
            TcpipRecBuff.ReadIndex=0;
            
        }
        else if(TcpipRecBuff.buff[TcpipRecBuff.ReadIndex] == 0)
        {
            *len=0;                         //如果缓冲区为空
        }
        else
        {                                  //缓冲区有数据,根据读出来的第一个字节往后读取指定的字节数
            memcpy(buff,&TcpipRecBuff.buff[TcpipRecBuff.ReadIndex+1],TcpipRecBuff.buff[TcpipRecBuff.ReadIndex]);
            *len=TcpipRecBuff.buff[TcpipRecBuff.ReadIndex];   
            tmp=TcpipRecBuff.buff[TcpipRecBuff.ReadIndex]+1;
            memset(&TcpipRecBuff.buff[TcpipRecBuff.ReadIndex],0,TcpipRecBuff.buff[TcpipRecBuff.ReadIndex]+1);
            TcpipRecBuff.ReadIndex += tmp;
        }
    return TRUE;
}

////////////////////////写缓冲区函数
uint8  BuffWrite(uint8* buff,uint8 len)
{
        if (TcpipRecBuff.BuffFull == 0)                 //自定的缓冲区读写,一个读指针,一个写指针。
        {
		if( (TcpipRecBuff.Index +len-1) > TCPIPBUFFSIZE-1) //当buff缓冲满标志被置1时,只有把缓冲区读取完才能清除满标志
		{
			TcpipRecBuff.BuffFull =1;         //这个分支判断缓冲区是否还有空间存入数据,如果没有,就把缓冲满标志置1
			memset(&TcpipRecBuff.buff[TcpipRecBuff.Index],0,TCPIPBUFFSIZE-TcpipRecBuff.Index); //并把最后没存的一段缓冲区清0
		}
		else
		{
			TcpipRecBuff.buff[TcpipRecBuff.Index++]=len;  //如果还有空间可以存,那么第一个字节填这一帧总共有多少个字节
			memcpy(&TcpipRecBuff.buff[TcpipRecBuff.Index],buff,len);//从第二个字节开始存一帧
			TcpipRecBuff.Index += len;
		}
	}
}

你可能感兴趣的:(一种通信接收缓冲区的操作想法)