移动物联网项目搭建(四)
功能设计
设计思考
在书写代码之前,一定要去思考一些项目架构的问题,这有助于我们能力的提升和代码书写效率的提高。
1. 我们具体要实现哪些功能?
对于监控端,我们要实现短消息的发送与接收,小图片的传输与接收和接收来自采集端采集到的温度数据。
2. 我们是否需要多线程,如果是的话需要几个线程?
对于上述的几个功能,我们可以了解我们既要能随时发送消息又要能随时接收消息且要随时接收来自采集端的温度数据,那我们就肯定要用到多线程,一个线程用来监听是否有发送事件到来,一个线程用来接收消息同时也可用来接收来自采集端的温度数据,故需用到两个线程,那么我们就设计一个主线程,一个副线程。
3. 我们是否需要多个界面,如果是的话需要几个界面?
根据上述的功能和主界面的设计情况,我们可能还需要一个Dialog界面用于回显所接收消息的详细信息和图片消息的图片,除此之外,我们可以再额外实现一个登录功能,需要一个登录界面作为Splash窗口。
4. 阿里云提供的C-SDK是纯C的代码,而QT工程是C++的代码,移植过程是否有需要注意的地方?
C语言的内容有99%都可以在C++中实现,有区别的地方不多,但我们这个项目着实遇到了移植相关的问题。这里分享一下移植的经验:
- 注意可变指针void*的使用,在C++中编译器更加严格,若要进行赋值或者传参之类的操作需要加上强制类型转换。
- 注意函数指针的用法,由于C++使用面向对象的思想,大多函数均封装为某个类的成员函数,而成员函数作为函数指针来使用会遇到许许多多的问题,这里不建议成员函数使用函数指针。
- 由于库文件连接的一些复杂性,这里建议将一些重要函数作为普通函数来直接使用,而不用封装为成员函数。
5. 消息发送接收的格式约定是怎样的?
在与云端的通信中,可以选择传二进制数据流,也可以选择传Json消息包,我们这里选择后者,然后约定一个消息的大致格式如下:
{
"type":"Text";
"data":"Hello, world!";
"note":"";
}
每个消息有三个属性:类型,数据和备注。
然后我们这里选择使用mjson包来实现json包的打包和拆包:官网链接:http://bolerio.github.io/mjson/
如果进不去可以下载我上传的资源:https://download.csdn.net/download/amorx12345/11441370
结合mjson库,编写了两个封装好的函数以供使用
char *new_entry(char *type, char *payload, char* note)
{
char *str;
json_t *entry, *label, *value;
entry = json_new_object();
//insert first label
label = json_new_string("type");
value = json_new_string(type);
json_insert_child(label, value);
json_insert_child(entry, label);
//insert second label
label = json_new_string("data");
value = json_new_string(payload);
json_insert_child(label, value);
json_insert_child(entry, label);
//insert third label
label = json_new_string("note");
value = json_new_string(note);
json_insert_child(label, value);
json_insert_child(entry, label);
json_tree_to_string(entry, &str);
return str;
}
将参数给定的属性封装为一个json格式的字符串返回。
void json_to_msg(char *type, char *data, char *note,char *payload)
{
json_t *root = NULL, *labelt, *labeld, *labeln;
json_t *valuet, *valued, *valuen;
json_parse_document(&root, payload);
labelt = json_find_first_label(root, "type"); //直接获取type所对应的值
valuet = labelt -> child;
strcpy(type, valuet->text);
labeld = json_find_first_label(root, "data"); //直接获取data所对应的值
valued = labeld -> child;
strcpy(data, valued->text);
labeln = json_find_first_label(root, "note");
valuen = labeln -> child;
strcpy(note, valuen->text);
}
将json格式进行解包,并将各规定好的属性放入参数指向的盘块区存储。
6.对图片的处理该如何进行?
图片文件实际也是二进制编码构成的,那我们首先要把二进制编码转换为字符串,再打包为json包进行发布,于是我们使用了Base64编码的方式实现。
Base64编码实现:
char *base64_encode(char *bindata, char *base64, int binlength)
{
int i,j;
unsigned char current;
char * base64char = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
for(i=0,j=0; i < binlength; i+=3)
{
current = (bindata[i] >> 2);
current &= (unsigned char)0x3F;
base64[j++] = base64char[(int)current];
current = ((unsigned char)(bindata[i] << 4)) & ((unsigned char)0x30);
if(i+1 >= binlength)
{
base64[j++] = base64char[(int)current];
base64[j++] = '=';
base64[j++] = '=';
break;
}
current |= ((unsigned char)(bindata[i+1] >> 4)) & ((unsigned char)0x0F);
base64[j++] = base64char[(int)current];
current = ((unsigned char)(bindata[i+1] << 2)) & ((unsigned char)0x3C);
if( i+2 >= binlength)
{
base64[j++] = base64char[(int)current];
base64[j++] = '=';
break;
}
current |= ((unsigned char)(bindata[i+2] >> 6)) & ((unsigned char)0x03);
base64[j++] = base64char[(int)current];
current = ((unsigned char)bindata[i+2]) & ((unsigned char)0X3F);
base64[j++] = base64char[(int)current];
}
base64[j] = '\0';
return 0;
}
Base64解码实现: