1. 程式人生 > >一種通訊接收緩衝區的操作想法

一種通訊接收緩衝區的操作想法

//////概述 在通訊中,比如UART。接收到的資料經常是一幀一幀而不是一個位元組一個位元組,上層應用在需要讀取通訊資料的時候通常希望讀取到的就是一個完整的幀,這樣比較方便解析。如果底層對上層提供的介面是Read(port,buff,len,timeout)這種形式的話,上層為了避免收到的buff不是完整的一幀,len經常定得比較大,這樣子的話就可能出現一種情況。假設底層接收到兩幀,都放到緩衝區,上層這時呼叫讀取介面,讀到的不只是一幀,是一幀還多一些,這個時候去解析的話,就會把後面那一部分丟掉,那麼下次再調底層介面讀取資料的時候就會是剩下的那一半,肯定解析不了,必須丟掉。上面這種情況只會出現在傳送方傳送得比較快,接收方來不及接收的時候。如果是通訊速度比較慢,接收方上層讀取通訊介面的速度比較快的話,就不會出現,因為根本不會出現緩衝區多於一幀的情況。實際上Linxu和Windows上的串列埠通訊介面都是採用這種方式,所以如果通訊速度快的話,都會出現丟幀的情況。下面這個程式就是為了解決這個問題,提出的一種想法。
實際通訊中,串列埠通訊都是有通訊格式規定的,下面這個程式可以配合具體的通訊協議做成傳輸層,構成  應用層--傳輸層--底層驅動  這種形式。







///////巨集定義
#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;
		}
	}
}