Taskbus - 基于Qt的跨平台多进程合作框架(四)跨架构数据封装

上一篇文章中,我们介绍了 taskBus 用到的Qt技术。实际应用时,如果在ARM系统下生产出数据,送到PC架构的服务器上处理,则需要考虑跨架构的数据封装。

1. TCP传输中的大小端问题

ARM架构是一种大端架构,对于我们的结构体:

	struct subject_package_header{
		//Always be 0x3C,0x5A,0x7E,0x69。
		unsigned char  prefix[4];
		unsigned int subject_id;
		unsigned int path_id;
		unsigned int data_length;
	};

在ARM架构下,subject_id 为1时,字节存储为

0x00,0x00,0x00,0x01

在PC的x86下,则为

0x01,0x00,0x00,0x00

如果通过TCP简单的跨架构传输,在生产者一方没有问题,在消费者这边,会发生错误。最糟糕的是,数据长度字段也是4字节的整数,发生错误后,会造成长度大小错误,有时引起内存耗尽。比如下图,ARM处理器上生成的结构体,length填写为1,到了PC端,则变为 0x01000000。系统将分配整块内存,并等待16777216字节的数据到来。

TCP Wrong

事实上,我们可以通过修改TCP传输模块,在其中加入大小端的判断来统一这个问题。
TASKBUS 约定在脱离某个具体的平台进程的所有数据,必须遵照 little endian 即小端在前(x86 PC)格式。对ARM来说,需要进行转换。

2. 关键参数大小端转换

taskBus中,提供了两个简易的函数完成大小端的转换:

	inline bool lendian()
	{
		static const short testv = 0x0102;
		static const unsigned char * testp = reinterpret_cast<const unsigned char *>(&testv);
		static const bool littled = (testp[0]==0x02)?true:false;
		return littled;
	}


	template <typename T>
	inline T cvendian(const T & v, bool tolittle)
	{
		if (lendian()==tolittle)
			return v;
		const size_t sz_len = sizeof(T);
		const unsigned char * p = reinterpret_cast<const unsigned char *>(&v);
		T res;
		unsigned char * q = reinterpret_cast<unsigned char *>(&res);
		for (size_t i=0;i<sz_len;++i)
			q[i] = p[sz_len-1-i];
		return res;
	}

在TCP模块 network_p2p中,采用上述工具确保传输的内容一定为小端在前, 比如在从外部接收TCP数据时,要把长度转换一次。下面的代码,若在PC上,因为本身即是小端,不会转换。在ARM上,会转换一次:

void DialogNetP2P::slot_read_sock(){
	//...
	const subject_package_header * pheader = (const subject_package_header *)
			m_package_array.constData();
	const unsigned int datalen =	cvendian(pheader->data_length,false);	
	//...
}

同样,在发送数据前,也要进行一次转换:

void DialogNetP2P::slot_new_taskpack(QByteArray package)
{
	//...
	const unsigned int wr_sub = cvendian(header.subject_id,false);
	const unsigned int wr_path = cvendian(header.path_id,false);
	const unsigned int wr_dtalen = cvendian(header.data_length,false);
	m_sock->write((const char *)header.prefix,4);
	m_sock->write((const char *)&wr_sub,sizeof(wr_sub));
	m_sock->write((const char *)&wr_path,sizeof(wr_path));
	m_sock->write((const char *)&wr_dtalen,sizeof(wr_dtalen));
	m_sock->write((const char *)fdata,header.data_length);
	//...
}

TCP Converted

3. 数据载荷的约定

通过上述转换后,TCP的收发正常了。但载荷内部的数据仍旧需要应用本身注意。比如,我们测量的土壤的温度是一个2字节的整数,要注意它们的转化。对8字节的double类型,不注意转化则会得到非常离奇的数字。

通过上述工作,我们实现了ARM与win32的分布式互联。

Arm And win10

发布了127 篇原创文章 · 获赞 330 · 访问量 48万+

猜你喜欢

转载自blog.csdn.net/goldenhawking/article/details/85215631