首页 > 代码库 > 高性能服务框架revolver:RUDP(可靠UDP)算法详解

高性能服务框架revolver:RUDP(可靠UDP)算法详解

数据块定义

在RUDP模块中,所有发送的数据被定义成RUDPRecvSegment 和 RUDPSendSegment结构,其中RUDPSendSegment是发送块定义,RUDPRecvSegment 是接收块定义。如下:

//发送数据片typedef struct tagRUDPSendSegment{	uint64_t	seq_;                          //块序号	uint64_t	push_ts_;		       //进入发送队列的时刻	uint64_t	last_send_ts_;		       //最后一次发送的时刻	uint16_t	send_count_;		       //发送的次数	uint8_t		data_[MAX_SEGMENT_SIZE];       //块数据		uint16_t	data_size_;                    //块数据长度}RUDPSendSegment;
typedef struct tagRUDPRecvSegment{	uint64_t	seq_;                          //块序号	uint8_t		data_[MAX_SEGMENT_SIZE];       //块数据	uint16_t	data_size_;	               //块数据长度}RUDPRecvSegment;

块的最大尺寸为MAX_SEGMENT_SIZE = 1408(不能大于MTU,一般MTU是1492)。为了加快内存分配的速度,RUDP模块中使用了对象池来保证块对象的快速申请,对象池定义:

ObjectPool<RUDPSendSegment, RUDP_SEGMENT_POOL_SIZE>	SENDSEGPOOL;ObjectPool<RUDPRecvSegment, RUDP_SEGMENT_POOL_SIZE>	RECVSEGPOOL;#define GAIN_SEND_SEG(seg) 	RUDPSendSegment* seg = SENDSEGPOOL.pop_obj();	seg->reset()#define RETURN_SEND_SEG(seg) 	if(seg != NULL)		SENDSEGPOOL.push_obj(seg)#define GAIN_RECV_SEG(seg) 	RUDPRecvSegment* seg = RECVSEGPOOL.pop_obj(); 	seg->reset()#define RETURN_RECV_SEG(seg) 	if(seg != NULL)		RECVSEGPOOL.push_obj(seg)

几个宏是作为块申请和释放的宏。以上就是块的定义介绍,更具体的只有去查看相关源代码了。

发送缓冲区

发送缓冲区,定义如下:

class RUDPSendBuffer{public:	...	//发送数据接口	int32_t				send(const uint8_t* data, int32_t data_size);	//ACK处理	void				on_ack(uint64_t ack_seq);	//NACK处理	void				on_nack(uint64_t base_seq, const LossIDArray& loss_ids);	//定时器接口	void				on_timer(uint64_t now_ts);	//检查BUFFER是否可以写入数据	void				check_buffer();	...public:	uint64_t			get_buffer_seq() {return buffer_seq_;};	//设置NAGLE算法		void				set_nagle(bool nagle = true){nagle_ = nagle;};	bool				get_nagle() const {return nagle_;};	//设置发送缓冲区的大小	void				set_buffer_size(int32_t buffer_size){buffer_size_ = buffer_size;};	int32_t				get_buffer_size() const {return buffer_size_;};	...protected:	IRUDPNetChannel*	net_channel_;	//正在发送的数据片	SendWindowMap		send_window_;	//正在发送的报文的丢包集合	LossIDSet			loss_set_;	//等待发送的数据片	SendDataList		send_data_;	//发送缓冲区的大小	int32_t				buffer_size_;	//当前缓冲数据的大小	int32_t				buffer_data_size_;	//当前BUFFER中最大的SEQ	uint64_t			buffer_seq_;	//当前WINDOW中最大的SEQ	uint64_t			cwnd_max_seq_;	//接收端最大的SEQ	uint64_t			dest_max_seq_;	//速度控制器	RUDPCCCObject*		ccc_;	//是否启动NAGLE算法	bool				nagle_;}

其中send函数是数据写入函数,在这个函数里面,缓冲区对象先会对写入的数据进行报文拼接成发送块,让发送数据尽量接近MAX_SEGMENT_SIZE,如果发送的数据大于MAX_SEGMENT_SIZE,也会进行MAX_SEGMENT_SIZE为单元的分片。然后写入到对应的发送缓冲列表send_data_当中。最后尝试进行网络发送。伪代码如下:

int32_t RUDPSendBuffer::send(const uint8_t* data, int32_t data_size){	int32_t copy_pos = 0;	int32_t copy_size = 0;	uint8_t* pos = (uint8_t *)data;	uint64_t now_timer = CBaseTimeValue::get_time_value().msec();	if(!send_data_.empty()) //拼接报文,让其接近MAX_SEGMENT_SIZE	{		//取出send_data_中的最后一片,如果它没有达到MAX_SEGMENT_SIZE,数据追加到MAX_SEGMENT_SIZE大小为止。		RUDPSendSegment* last_seg = send_data_.back();		if(last_seg != NULL && last_seg->data_size_ < MAX_SEGMENT_SIZE)		{			copy_size = MAX_SEGMENT_SIZE - last_seg->data_size_;			if( copy_size > data_size) 				copy_size = data_size;			memcpy(last_seg->data_ + last_seg->data_size_, pos, copy_size);			copy_pos += copy_size;			pos += copy_size;			last_seg->data_size_ += copy_size;		}	}	//剩余数据分成MAX_SEGMENT_SIZE为单位的若干分片	while(copy_pos < data_size)	{		GAIN_SEND_SEG(last_seg);		//设置初始化的的时刻		last_seg->push_ts_ = now_timer; //记录压入时间戳		last_seg->seq_ = buffer_seq_;		buffer_seq_ ++;		//确定拷贝的块长度		copy_size = (data_size - copy_pos);		if(copy_size > MAX_SEGMENT_SIZE)			copy_size = MAX_SEGMENT_SIZE;		memcpy(last_seg->data_, pos, copy_size);		copy_pos += copy_size;		pos += copy_size;		last_seg->data_size_ = copy_size;		//压入发送队列		send_data_.push_back(last_seg);	}	//记录缓冲区的数据长度	buffer_data_size_ += copy_pos;	//尝试发送,立即发送	attempt_send(now_timer);	return copy_pos;}

这里会触发attempt_send()函数。这个函数是尝试发送的核心函数。在后面的几个过程里面也会调用到这个函数。以上就是发送函数的过程。 

高性能服务框架revolver:RUDP(可靠UDP)算法详解