知识点没有顺序:
按照A4纸整理
1、 关于DaemonConfig.ini
可以设置多播的数值,如果希望多台设备共同接收数据火或者发送数据,则将多播的IP地址和端口号设置相同
如果接收到的主题混乱,在使用上面方式之后,仍然没有用,可以考虑改变字符编码格式。
2、 对于全局变量的使用
如果一个变量只是在本类中使用,将这个变量定义为成员变量;
对于static类型的回调函数,在这个函数里使用成员变量,有两种解决方法:
(1) 将成员变量定义为static,在类外初始化
(2) 定义本类指针,例如:static CompInfoRecv *g_CompInfoRecvPtr;
使用静态本类指针调用成员变量,例如:g_CompInfoRecvPtr->m_Index,这样在回调函数中可以使用成员变量,同时不需要将成员变量设置为static.
使用全局变量的时候,会结合extern关键字,这个有什么作用呢?
答:C++允许将定义和声明分离开来。
变量的声明规定了变量的类型和名字,即使一个名字被程序所知。一个文件如果想使用别处定义的名字则必须包含对那个名字的声明。
定义则负责创建与名字关联的实体,定义还申请空间存储。
如果向声明一个变量而非定义它,就在变量名之前加extern关键字,而不要显式地初始化变量;
例如:
extern int i; //声明i,而非定义I
注意:一个文件中这样声明i,如果想要i正常使用,必须在其他地方对i进行了初始化
如果i在一个文件中已经声明定义,则在另一个文件中,使用extern int i,则在这个文件中不需要重新定义I,并且可以正常使用i;
Int j; //声明并且定义j
但是我们也可以使用extern关键字给变量一个初始值,但这样就不是一个声明了,而是一个定义
Extern int v=2;
Int v=2;
//这两个语句完全一样,都是v的定义。
补充:
1、 将变量设置为全局变量,意将这个变量为所有类共享
2、 如果变量只是在本类中使用,将这个变量定义为成员变量
3、 对于static回调函数里面使用的变量不一定要是static,可以使用static类型的本类对象调用这些成员变量
4、 全局变谨慎使用
一般全局变量会被定义为指针类型,指针本身只占用4个字节,这样不会占用太多内存
5、 使用extern时,需要包含变量定义所在的头文件
extern只是声明这个变量,需要包含对应的头文件这样才可以找到变量定义的位置。
3、 全局变量、局部变量、类成员变量
错误的使用:
//全局变量
Char* filePath=”C:/ComponentRepository/”;
Void EvoSphere::CompInfoRecv::CreateCompontPack。et(const char compName)
{
//将组件名拼接到路径的后面
string tmpCompPath;
tmpCompPath.assign(EVO_COMPONENT_REPOSITORY_ROOT_DIR).append((char)compName).append("/");
//自动创建文件夹
createNewFileDir((char*)tmpCompPath.data());//string 转 char*
filePath=(char*) tmpCompPath;
printf(“OnFuncCompRequestRecv fileNamePath totalPath=%s\n”, fileNamePath);
}
//注意:这样写肯定是错误的:
将局部变量tmpCompPath赋值给filePath,这时候这两个指针指向同一块内存,当这个函数运行结束后,这个局部变量的所指向的内存将会被释放,这时候指针filePath将变为野指针。同时也没有实现路径保存的效果。
解决方法:
在类中定义成员变量char数组
Char filePath[256];
Void EvoSphere::CompInfoRecv::CreateComponentPacket(const char compName)
{
//将组件名拼接到路径的后面
string tmpCompPath;
tmpCompPath.assign(EVO_COMPONENT_REPOSITORY_ROOT_DIR).append((char)compName).append("/");
//自动创建文件夹
createNewFileDir((char*)tmpCompPath.data());//string 转 char*
strcpy(fileNamePath, tmpCompPath.c_str());
printf(“OnFuncCompRequestRecv fileNamePath totalPath=%s\n”, fileNamePath);
}
将路径保存到新开辟的内存空间中,这样局部变量释放后,路径仍然被保存下来。
4、 关于调试
出现的问题:当前不会命中断点,还没有为该文档加载任何符号
错误原因:进行调试的程序与你当前打断点的地方是不一致的
若想调试CompCtrlMonitorLib中的代码,其对应的exe程序是NodeAgent.exe
应该调试NodeAgent.exe程序。
我的错误是:调试了DeployMonitorTool.exe
5、 关闭文件异常fclose(fp)
关闭文件的时候会把内存缓冲区中的数据刷到文件里
可能关闭文件失败的原因:向文件中写了很多的数据(假设内存放的下),但是磁盘上没有空间了,这个时候,你一旦fclose(fp),这么多的数据就会刷到文件中,此时磁盘是装不了这么多的数据的。所以会关闭文件异常
if (s_configInfo.s_filePtr != NULL)
{
if (fwrite(iMessage, iLen, 1, s_configInfo.s_filePtr) != 1)
{
printf(“OnCompInfoRequest 写入文件失败!\n”);
return;
}
fflush(s_configInfo.s_filePtr); //将数据从内存缓冲区刷到文件中
}
关闭文件异常还有可能是:文件没有正常打开,文件句柄为NULL
6、 关于发送数据与接收数据包的格式
CompInfoSend.h CompInfoRecv.h
注:接收数据的回调函数使用了很多巧妙的方法,值得多看几遍。
组件id 序列号 有效长度 文件包
- 文件包里存放着每次发送的数据段Message
- 根据序列号,得知文件包里存放的数据类型
- 规范化结构体可能会浪费一点内存空间
- 对于通讯而言(文件传输):数据安全性优于数据传输速率
- 文件句柄打开或关闭的延时不要太长
发送端数据结构体:
//4+4+4+1024
struct MsgFileBlock
{
int s_Id; //文件标识
int s_SerialNum; //序列号
int s_Length; //文件包的有效长度
char s_BlockBuf[1024]; //文件包大小
char s_BlockTotalBuf[1036]; //整个文件包的大小
//结构体里可以构造无参、有参构造函数,也可以编写各种函数,像类一样使用
MsgFileBlock()
{
s_Id = 0;
s_SerialNum = 0;
s_Length = 0;
memset(s_BlockBuf, ‘0’, 1024);
memset(s_BlockTotalBuf, ‘0’, 1036);
}
}MsgBlock;
7、