今天总结一下之前node.js的C++Addon的项目,去交流后,否决了之前把MacDataTransfer.lib和dll再次封装成为node可用的.node文件的方案,因为这个转换的MacDataTransfer对象和存储解析结果的ST_SEND_RTCM32_MSG结构体都要求声明为全局变量并一直保持运行,而这在之前的方案是做不到的。所以换成了整个“接收——输入——解析”的流程都在VC++平台上完成的方案,之后再把解析结果封装成JSON再发送出去。

为此我算是重新拾起两年没写的C++,小到数据类型转换和读取,大到多线程和TCP SOCKET,都重新温习了一遍。虽然最后只写了一个200+行的小程序,但也用到了不少东西,在这里记录下来。


数据类型

C++的数据类型都比较原始,大致说来就是往下一走就是内存,因而不同类型的数据转换须小心谨慎。比如说unsigned char转换成char,一个unsigned字符需要占用两个char的位置,因为unsigned char是-127—127的,而char是0—255,为保证数据不丢失,需要相应的内存去储存它们。


数据转换和读取

有了对数据类型在内存中的性质的了解,进行数据转换就有的放矢了。

说白了数据的转换就是新建一个目标数据类型的变量a,把源数据类型的变量b所指的内存中的编码?字符?反正是这些东西拷贝到a中,如果数据在拷贝过程中没有丢失,那么应该就算是转换成功。

常见的拷贝方法

  1. 直接赋值
  2. 内存拷贝(memcpy)这是C的方法,很多C的方法其实都很好用
  3. 最强的,sprintf(),这也是C的方法,它相当于把printf的打印目的从终端改为目标地址(即我们的变量、数组什么的)。

基本用法是第一个参数是目标地址(字符串类型),第二个参数是格式化控制:如“%2d”,“%6.2X”等等,能用于控制打印格式,这个也是它的精髓,甚至我们可以“%*X”,随后在后面用变量来规定格式,比如:

sprintf(dest,"%*X",len,origin);    // dest:目标字符串,len:对应"*"位置的参数,origin:源数据

这也是为什么说sprintf强大的原因,比如在一些存储Unicode字符,16进制字符这些特殊类型的数组,我们调试时它们会被VS显示为无效字符,因为它们如果被理解为ASCII码,将是一大堆非打印字符。这时候我们在VS中可以使用

添加监视————在监视窗口中,在名字后面加上".x"来显示为16进制形式,unicode也有相应的参数

我一开始在尝试解析的时候,看到一堆非打印字符,一脸懵逼(这也是源于无知,我并不了解它们是16进制的,也不知道如何查看16进制的值)。

sprintf就能很好的执行数据转换的功能,我们可以使用它,很方便的把unsigned 类型的原始数据转换为我们想要的。它还可以从结构体数组中很方便地获取其中的数组等等类型数据而不需要预设get()方法,而这个memcpy是做不到的。

sprintf甚至可以用于拼接字符串,代替strcat(),只需把后面的源数据实际参数,改成多个就可以了。


TCP SOCKET

说来惭愧,我的C++从来都没有写过除了算法之外的东西,所以这些算是首次接触。

我们的TCP SOCKET也不是特别复杂,同步类型的比较简单,因为我写的这个程序目前只需要从单源接收,转发给单目标,所以我只写了同步的。

TCP SOCKET同步下也没什么坑,但是它的recv函数说实话比较鶸,而相反UDP协议下的recvfrom函数就能获取我们本次收到的字节数。这个相当赞。因为我们的转换函数的入口是需要数据长度的(在这里再次吐槽C++的数组,实在是太原始了)。幸好我们TCP SOCKET也能使用recvfrom函数(是在connect函数后使用,意味着是client才能用?),这个函数的返回值就是接收长度。


多线程

上面提到过了,我写的这个程序目前只需要从单源接收,转发给单目标,所以多线程方面也不太需要很多线程,我只需要写成一个收线程(输入),一个发线程(解析——封装——发送),然后按最简单的”生产-消费者“模型,设置一个互斥量就可以完成了。

C++多线程在windows下依赖windowsAPI,所以需要包含<windows.h>头文件。

DWORD WINAPI RecT(LPVOID lpParameter) {while (true) {WaitForSingleObject(hMutex, INFINITE);cout << "写入缓冲区" << endl;len = recvfrom(socketclient, szRecv, 2048, 0, (struct sockaddr*)&sourceAddr, fromlen);cout << "输入数据,长度为:" << len << endl;ReleaseMutex(hMutex);}return 0L;
}DWORD WINAPI sendT(LPVOID lpParameter) {int errMsg = 0;WSADATA wsaData;WSAStartup(MAKEWORD(2, 2), &wsaData);SOCKET servSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);/*int result_set = setsockopt(servSocket, IPPROTO_TCP, TCP_NODELAY, (char*)&f, sizeof(f));if (result_set==0){cout << "设置socket,关闭Nagle成功" << endl;}*/sockaddr_in servAddr; memset(&servAddr, 0, sizeof(SOCKADDR)); //memset(&)servAddr.sin_family = AF_INET; servAddr.sin_port = htons(2019); servAddr.sin_addr.s_addr = inet_addr("192.168.3.339"); ::bind(servSocket, (SOCKADDR *)&servAddr, sizeof(SOCKADDR));listen(servSocket, 20);destSocket = accept(servSocket, (SOCKADDR *)&servAddr,&nSize);while (true) {WaitForSingleObject(hMutex, INFINITE);cout << "解析数据" << endl;errMsg = send(destSocket, msg_send.c_str(), msg_send.length()*sizeof(const char),0);ReleaseMutex(hMutex);if (SOCKET_ERROR == errMsg){closesocket(destSocket);listen(servSocket, 20);destSocket = accept(servSocket, (SOCKADDR *)&servAddr, &nSize);   }}return 0L;
}

基本上简单的带互斥量的一个轮换的模型就是这样子。如果要真正实现生产者——消费者模型,还得设置两个全局变量full和empty。

我在发送进程中添加了防止客户端掉线之后仍然往原来的socket发送数据的代码,就是利用send()函数发送失败会返回-1的特点。


JSON for modern C++

这是一个德国大神写的C++下的JSON库,优点在于简便(只需包含json.hpp一个头),单元测试全覆盖(所有异常都能覆盖,捕捉到),可谓相当的强大。

但是我是上学期末才开始接触node.js,而我理解JSON是从JavaScript衍生出来的,JSON的方法我算是一窍不通。

我封装JSON的过程需要解决以下几个问题:

  1. 我们的解析结果有相当多的冗余数据,我需要一一剔除,这也是我为什么需要从结构体数组里提取数据的原因。这个ST_SEND_RTCM32_MSG结构体虽然关于存储数据的数组的长度有标志元素,但是它很(和谐)地设置了一个默认值,默认长度是满的,如果这个数组是空的,也就是没有这个数据,那么相应的标志元素就不会得到修改,所以整个数组就是满满的"0"(所有未赋值的位置都被初始化为"0")。

  2. 我需要判断数据是否存在,动态的加入到JSON中,这意味着我不能用直观的静态赋值的方式。

-----------------------------------                我是分界线            --------------------------------------

我的解决方法如下:

  1. 剔除冗余数据我用循环sprintf的形式,顺便转换了数据形式。对于它们有可能为空但是标志元素却是满长度的情况下,我们大胆推测它不可能满,满就是空。

  2. 动态加入JSON我是用JSON_PATCH + 修改对应的值的方式来实现的,先用JSON PATCH的方式添加一个键值对,值初始化为随便一个字符(因为JSON PATCH补丁不支持变量的值好像),随后用json.at()=???的方式,用赋值形式修改相应键的值就好了。

json msg;
msg = R"({ "name":"grid"})"_json;
msg.at("name") = i;
if (stRoverRtCM32Msg[i]->nByte != 1024) {for (int j = 0; j < stRoverRtCM32Msg[i]->nByte; j++)sprintf(my_pbuf + j * 2, "%02X", stRoverRtCM32Msg[i]->pbuf[j]);json j_Patch = R"([{"op": "add", "path": "/MT1074", "value": "B"}])"_json;msg = msg.patch(j_Patch);msg.at("MT1074") = my_pbuf;}

勤学勤记(四)——放弃Addon,选择纯C++相关推荐

  1. 李学勤:功利化是现在教育的最大问题

    李学勤先生千古! 学位不能简单地做成"通用粮票" 记:您对现行的学位制度有什么看法? 李:先简单回顾一下我国学位制度的历史.建国以前,没有一个系统的学位制度,从来没有颁布过正式的博 ...

  2. 技术学习之路漫漫其修远兮,奋力勤学吾辈将上下而求索

    引言:计算机的生活应用场景 生活在高科技快速发展年代的我们发现被各种"APP"(微信.微博.抖音...)所包围,而这些"app"都有一个共同的"后台& ...

  3. 计算机专业勤学善思感悟,勤学善思作文600字

    自隋朝以来,我国就对教育极为重视,身为二十一世纪的我们,深深的知道学习的重要性,只是如今的我们似乎已经对教育的真正含义产生了误解,我们是对教育重视,但是我们更对学习成绩重视,学习成绩真的是我们实行教育 ...

  4. 王阳明:<二> 立志,勤学,改过,责善

    明武宗正德元年,王阳明因反对宦官刘瑾,被贬至贵州龙场的荒僻之地.在龙场这既安静又困难的环境里,王阳明在一种困顿和痛苦之中,结合自己历年来的遭遇,日夜反省,终于在一天半夜豁然大悟,认识到"圣人 ...

  5. 计算机专业勤学善思感悟,做一个勤学善思的人演讲稿

    做一个勤学善思的人演讲稿 李时珍一心为民,他为了改进<本草经>的不足,走遍了出产药材的名山,学到了许多书本上并没有记载的知识,增添了许多药理 学问.他花了整整27年的时间,终于编写成了一部 ...

  6. 陶渊明劝学——勤学如春起之苗

    相传陶渊明归隐后,一天,有个少年向他求教:"先生,我十分敬佩你渊博的学识,很想知道你少年时读书的妙法,敬请传授,晚辈不胜感激."陶渊明听后,大笑道:"天下哪有学习妙法?只 ...

  7. 勤学修身 放飞梦想4

    美好的 人生 ,从美好的梦想开始. 美好的梦想,是吹面不寒的杨柳风,是润物细无声的春雨,带给你人生的灿烂,带给你事业的辉煌.美好的梦想,是潺潺的小溪,一路奔波,一路高歌,自会有江河的波澜壮阔,自会有 ...

  8. 公摊面积取消闹乌龙,历史学家李学勤逝世,微软员工抗议国防大单,前摩拜CEO后花68万上学,这就是今天的大新闻。...

    今天是2月25日 农历正月廿一 今天星期一 大家看起来 都好像很兴奋 下面是今天的大新闻 "公摊面积"要取消? 央视:这是错误理解 (今日头条)近日有关"公摊面积&quo ...

  9. 《数据结构》天勤和王道 第四章 串

    <数据结构>天勤和王道 第四章 串 天勤部分 1. 串的基础 1.1 逻辑结构 1.2 存储结构 1.3 赋值操作 1.4 串比较 1.5 串连接 1.6 求子串 1.7 清空串 2. K ...

最新文章

  1. 最新机器学习开源项目Top10
  2. 多目标检测跟踪文献代码汇总
  3. verilog中对inout信号的处理
  4. python批量提取word指定内容到excel_(转)用python批量读取word文档并整理关键信息到excel表格...
  5. 【Java代码】道格拉斯-普克 Douglas-Peucker 抽稀算法分析及15w个坐标点抽稀到3.7w耗时从360s+优化到365ms接近1000倍的速度提升源码分享(并行流+多线程+泛型)
  6. 程序员的项目周期(表情包版)
  7. 模块化 组件化 工程化_软件工程中的模块和软件组件
  8. TCP协议的部分解析(1)
  9. 微信Windows 3.3.0内测发布 可以刷朋友圈了
  10. asp.net oracle 分页,asp.net教程之利用ASP实现Oracle数据记录的分页显示
  11. eclipse代码格式化
  12. [转载] [Python基础语法]关键字、标识符和变量
  13. 热释电红外传感器电路
  14. sem与seo的区别
  15. [渝粤教育] 西南科技大学 仓储与配送管理 在线考试复习资料
  16. iOS监听模式系列之本地通知Notification
  17. Centos7安装JDK【FinalShell终端本地文件上传失败解决办法】
  18. java 基本数据类型所占字节数
  19. 二维数组的定义和使用
  20. 分子对接及结果分析在线工具

热门文章

  1. 苹果手机计算机怎么放桌面,苹果手机iPhone装了App在桌面找不到图标的解决办法...
  2. app:processDebugManifest 错误
  3. Android热更新,Android面试题整理
  4. 适配Android Q指南
  5. 【Internet Explorer】IE11卸载不干净导致无法安装IE10
  6. 心과 情의 調和 (韓長庚 易學原理總論)
  7. 从ADK的WinPE自己手动构建自己的PE
  8. postman后端返回的数据显示中文乱码解决
  9. html th中加斜杠,vue element 表头添加斜线
  10. LeetCode 714 买卖股票的最佳时机含手续费