golang实现ringbuffer(不定长)

     每个数据包写入ringbuffer的存储结构:

     packet_size:uint16 | packet_ctx:byte[ ]

     整个ringbuffer的结构:

    ----------<——start:读的位置

    packet1

    ----------

    packet2    

    --------<——start+use:写的位置

    ……

type Ringbuffer struct{
	start,use int
	buf []byte 
}

       ringbuffer中buf为存储数据内容,start为读的位置的index,use为ringbuffer中未读数据包的字节数,start+

use便是写的位置。

      实现要点一:绕回

      ringbuffer是一个环,写入到尾部之后需要绕回到尾部,由于数据包是不定大小,所以到了尾部可能会出现数

据包一半在尾部一半在开头,对应的读取的时候数据包一半在尾部,一半在开头需要把它们合并起来。

     实现要点二:写入过快,释放覆盖

     当写入速度大于读取速度时,新写入数据会与未读数据发生覆盖,这样就有两种决策:覆盖未读数据和丢弃新

写入数据。

     实现要点三:避免重复读取

     由于ringbuffer是通过覆盖写入数据,并不会删除未读数据,所以就通过ringbuffer中的use来判断是否还有未读

数据。

package ringbuffer
import(
	"fmt"
)
type Ringbuffer struct{
	start,use int
	buf []byte 
}
func IntToByte(n int) []byte{
	buf:=make([]byte,4)
    buf[3] =  (byte)((n>>24) & 0xFF) 
    buf[2] =  (byte)((n>>16) & 0xFF)  
    buf[1] =  (byte)((n>>8) & 0xFF)    
    buf[0] =  (byte)(n & 0xFF);  
	return buf
}
func ByteToInt(buf []byte) int{
	var value int    
    value = (int)((buf[0] & 0xFF)|((buf[1] & 0xFF)<<8)|((buf[2] & 0xFF)<<16)|((buf[3] & 0xFF)<<24))
    return value; 
}
func NewRingbuffer(size int) *Ringbuffer{
	return &Ringbuffer{0,0,make([]byte,size)}
}//覆盖未读数据包策略
func (r *Ringbuffer) WriteCover(b []byte) bool {
	block_size:=len(b)
	if block_size > 0 {
		size:=len(r.buf)
		start:=(r.start+r.use)%size
		size_byte:= IntToByte(block_size)
        /*判断是非会覆盖未读block,
		  是的话,修改r.start */
		flag:=block_size+len(size_byte)
		for flag > (r.start-start+size)%size &&r.use!=0 {
			rblock_size:= ByteToInt(r.buf[r.start:r.start+4])			
			r.start = (r.start + rblock_size + 4)%size
		}
		//保存block的长度
		n:=copy(r.buf[start:],size_byte)
		if start+len(size_byte) > len(r.buf){
			copy(r.buf,size_byte[n:])//判断是否需要绕回
		}
		start = (start+len(size_byte))%size
		//保存block的内容
		n =copy(r.buf[start:],b)
		if start+len(b) > len(r.buf){
			copy(r.buf,b[n:])//判断是非需要绕回
		}
		start = (start+block_size)%size
		//更新ringbuffer的使用量
		r.use = (start+size-r.start)%size
		return true
	}
	return false
}//丢弃新写入策略
func (r *Ringbuffer) Write(b []byte) bool {
	block_size:=len(b)
	if block_size > 0 {
		size:=len(r.buf)
		start:=(r.start+r.use)%size
		size_byte:= IntToByte(block_size)
		//判断ringbuffer是否还有空间存放block
		end:=(start+len(b)+len(size_byte))
		flag:=end-len(r.buf)
		if flag>0 && flag > r.start {
			return false
		}	
		//保存block的长度
		n:=copy(r.buf[start:],size_byte)
		if start+len(size_byte) > len(r.buf){
			copy(r.buf,size_byte[n:])
		}
		start = (start+len(size_byte))%size
		//保存block的内容
		n =copy(r.buf[start:],b)
		if start+len(b) > len(r.buf){
			copy(r.buf,b[n:])
		}
		start = (start+block_size)%size
		//更新ringbuffer的使用量
		r.use = (start+size-r.start)%size
		return true
	}
	return false
}
func (r *Ringbuffer) Read(b []byte) int{
	if r.use > 0 {//判断是非还有未读数据
		//获取block的长度
		size_byte:=make([]byte,4)
		t:=copy(size_byte,r.buf[r.start:])
		if t!=4 {//判断有没有被分割开
		   copy(size_byte[t:4],r.buf[:])
		}
		rblock_size:= ByteToInt(size_byte)
		//获取block的内容
		start:=(r.start+4)%len(r.buf)
		nread:=0
		if start+rblock_size >= len(r.buf) {
		     n:= copy(b,r.buf[start:])//判断数据包内容有没有被分割
		     nread = copy(b[n:],r.buf[:])
		     nread = nread + n
		}else{
		    nread = copy(b,r.buf[start:start+rblock_size])
		}	
		if nread == rblock_size {
		     r.start = (r.start + rblock_size + 4)%len(r.buf)
		     r.use = r.use - rblock_size - 4
		     return nread
		}else{
			return -1
		}
	}
	return 0
}
func (r *Ringbuffer) GetUse() int{
	return r.use
}





你可能感兴趣的:(golang,数据结构)