网络游戏分包思考

本文探讨了网络游戏中的数据包处理,强调了快速响应的重要性。针对大数据量的情况,建议在业务层添加协议进行分割和重组。分析了skynet代码中的databuffer_read函数和消息处理流程,展示了如何通过缓冲区和动态调整读取字节数提高效率,并提供了直接处理数据包的方法。
摘要由CSDN通过智能技术生成

网络游戏由于对消息的响应速度有着比较高的要求,常常需要将tcp数据流分割成一个个的数据包。将数据流转换成数据包,常用的格式就是给数据包加一个长度组装在数据流中。

数据包长度的选择,你可以选择2个字节的长度也就是64K的字节信息表示一个包长,也可以选择4字节的包长作为长度的信息。

但是前面已经说过,由于游戏要求比较快速的响应,那么如果你允许一个tcp链接中插入一个太大的数据块,在网络比较脆弱的时候处理这个大块的时间就十分的长了,而且在业务的处理中,大块会阻塞信道,导致需要速度的操作得不到快色的响应,大块后面的数据都被延迟了。

在实际的业务中也有少许的场景是数据量比较大的,在这种场景中,我们最好是在业务的上层再添加一个协议,在具体的业务中去解析。比如查看游戏中的交易信息,如果交易信息很大,你可以先分割之后再在业务层去重新组合,你只需要在上层业务协议中加一个消息的长度即可。

也可以直接在长度 + 内容的基础上加一个大包的协议,具体可以是这种 所有的包都是id + 长度 + 内容,发送的时候将大包分割,接受的时候按照id重组,其实这样一来还不如在业务的内容中添加一个消息的长度,在业务的上层进行重组。

关于组包的思路:

这里skynet里面的代码可以给我们一个很好的启示:

 

 

#define MESSAGEPOOL 1023

struct message {
	char * buffer;
	int size;
	struct message * next;
};

struct databuffer {
	int header;
	int offset;
	int size;
	struct message * head;
	struct message * tail;
};

struct messagepool_list {
	struct messagepool_list *next;
	struct message pool[MESSAGEPOOL];
};

struct messagepool {
	struct messagepool_list * pool;
	struct message * freelist;
};

// use memset init struct 

static void 
messagepool_free(struct messagepool *pool) {
	struct messagepool_list *p = pool->pool;
	while(p) {
		struct messagepool_list *tmp = p;
		p=p->next;
		skynet_free(tmp);
	}
	pool->pool = NULL;
	pool->freelist = NULL;
}

static inline void
_return_message(struct databuffer *db, struct messagepool *mp) {
	struct message *m = db->head;
	if (m->next == NULL) {
		assert(db->tail == m);
		db->head = db->tail = NULL;
	} else {
		db->head = m->next;
	}
	skynet_free(m->buffer);
	m->buffer = NULL;
	m->size = 0;
	m->next = mp->freelist;
	mp->freelist = m;
}

static void
databuffer_read(struct databuffer *db, struct messagepool *mp, void * buffer, int sz) {
	assert(db->size >= sz);
	db->size -= sz;
	for (;;) {
		struct message *current = db->head;
		int bsz = current->size - db->offset;
		if (bsz > sz) {
			memcpy(buffer, current->buffer + db->offset, sz);
			db->offset += sz;
			return;
		}
		if (bsz == sz) {
			memcpy(buffer, current->buffer + db->offset, sz);
			db->offset = 0;
			_return_message(db, mp);
			return;
		} else {
			memcpy(buffer, current->buffer + db->offset, bsz);
			_return_message(db, mp);
			db->offset = 0;
			buffer+=bsz;
			sz-=bsz;
		}
	}
}

static void
databuffer_push(struct databuffer *db, struct messagepool *mp, void *data, int sz) {
	struct message * m;
	if (mp->freelist) {
		m = mp->freelist;
		mp->freelist = m->next;
	} else {
		struct messagepool_list * mpl = skynet_malloc(sizeof(*mpl));
		struct message * temp = mpl->pool;
		int i;
		for (i=1;i<MESSAGEPOOL;i++) {
			temp[i].buffer = NULL;
			temp[i].size = 0;
			temp[i].next = &temp[i+1];
		}
		temp[MESSAGEPOOL-1].next = NULL;
		mpl->next = mp->pool;
		mp->pool = mpl;
		m = &temp[0];
		mp->freelist = &temp[1];
	}
	m->buffer = data;
	m->size = sz;
	m->next = NULL;
	db->size += sz;
	if (db->head == NULL) {
		assert(db->tail == NULL);
		db->head = db->tail = m;
	} else {
		db->tail->next 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值