干货十足,惊为佳作,五年“划水”经验总结(持续更新)

29.[B/S模式]快速构建发布

先安装nodejs,再用vscode打开前端vue文件夹,// install dependencies  [npm install] 。

// develop [npm run dev]  ## Build [npm run build]。

build之后会有一个dist文件夹,部署nginx,配置conf文件夹中内nginx.conf文件,然后start nginx。

启动后端服务,c++或者java。最后打开浏览器,访问nginx.conf文件预设的主页地址即可。

 

28.脱离IDE工具编译,使用cmake+msbuild一键发布部署(入门级)

前提条件:
环境变量[path] -> cmake路径:D:\Program Files\CMake\bin
环境变量[path] -> msbuild路径:D:\Program Files (x86)\Microsoft Visual Studio\2017\Professional\MSBuild\15.0\Bin\amd64
--------备注(一定要确认好本机上安装的是专业版还是企业版,否则会报错某个文件缺失)

具体步骤:
第一步:新建一个build目录
示例:E:\cmake_sys\gtest-cmake-example-master\build
第二步:win+r 打开命令行界面 输入
cd /d E:\cmake_sys\gtest-cmake-example-master\build
第三步:在命令行界面 输入
cmake -G "Visual Studio 15 2017 Win64" E:\cmake_sys\gtest-cmake-example-master
第四步:在命令行界面 输入
msbuild ALL_BUILD.vcxproj /t:Rebuild /p:configuration=RelWithDebInfo
第五步:写bat脚本,一键发布部署

@echo off
setlocal enabledelayedexpansion
echo currentBatDir:%~dp0

set vcxprojDir=%~dp0%build
mkdir %vcxprojDir%
cd /d %vcxprojDir%

cmake -G "Visual Studio 15 2017 Win64" %~dp0
msbuild ALL_BUILD.vcxproj /t:Rebuild /p:configuration=RelWithDebInfo
echo build ok
pause exit

27.使用QT开源接收机软件(Gqrx),搭配硬件RTL2832U RTL-SDR USB

软件无线电,这款软件主要就是频谱图+瀑布图展示,观察信号频率。对于模拟信号进行识别解调获取音频数据。

26.使用json_rpc_cxx框架

类似于rest_rpc,但是个人认为这个框架水平要高一些(在代码编写层次上)

 核心代码如下:

 1  JsonRpc2Server rpcServer;
 2 
 3   // Bindings
 4   WarehouseServer app;
 5   rpcServer.Add("GetProduct", GetHandle(&WarehouseServer::GetProduct, app), {"id"});
 6   rpcServer.Add("AddProduct", GetHandle(&WarehouseServer::AddProduct, app), {"product"});
 7   rpcServer.Add("AllProducts", GetHandle(&WarehouseServer::AllProducts, app), {});
 8 
 9   // 本地跨进程调用
10   cout << "Running in-memory example" << "\n";
11   InMemoryConnector inMemoryConnector(rpcServer);
12   doWarehouseStuff(inMemoryConnector);
13 
14   // 网络跨进程调用(服务端)
15   cout << "Running http example" << "\n";
16   CppHttpLibServerConnector httpServer(rpcServer, 10086);
17   cout << "Starting http server: " << std::boolalpha << httpServer.StartListening() << "\n";
18   // 网络跨进程调用(客户端)
19   CppHttpLibClientConnector httpClient("localhost", 10086);
20   std::this_thread::sleep_for(0.5s);
21   doWarehouseStuff(httpClient);

统一抽象层,和普通函数类似的无差别调用

 1 void doWarehouseStuff(IClientConnector &clientConnector)
 2 {
 3   JsonRpcClient client(clientConnector, version::v2);
 4   WareHouseClient appClient(client);
 5   Product p;
 6   p.id = "0xff";
 7   p.price = 22.4;
 8   p.name = "Product 1";
 9   p.cat = category::cash_carry;
10   // 抽象层。新增“产品”,已存在的对象会执行失败
11   cout << "Adding product: " << std::boolalpha << appClient.AddProduct(p) << "\n";
12 
13   // 抽象层。获取指定“产品”(存在的情况)
14   Product p2 = appClient.GetProduct("0xff");
15   cout << "Found product: " << p2.name << "\n";
16   try {
17     // 抽象层。获取指定“产品”(不存在的情况)
18     appClient.GetProduct("0xff2");
19   } catch (JsonRpcException &e) {
20     cerr << "Error finding product: " << e.what() << "\n";
21   }
22 
23   // 抽象层。获取所有“产品”
24   auto all = appClient.AllProducts();
25   for (const auto &p: all) {
26     cout << p.name << endl;
27   }
28 }

25.编译并使用Nulloy

使用带有波形进度条的控件,让声音可视化,不做盲目的“管理者”。(使用qmake)

24.编译并使用QGIS

源代码编译预计俩个半小时,根据电脑配置有所差异。准备编译环境需要半天,有一点费功夫。(使用cmake)(RelWithDeb:生成可调试的release发布版本)

23.使用rest_rpc框架

基本执行流程:服务端将内部实现的函数以字符串的形式注册在缓存中,等待客户端远程调用触发;而客户端写回调函数来响应服务端的执行结果。具体效果如下:

(业务场景是,客户端将一个字符串参数通过该框架传递给相应的功能函数(在服务端的两个函数分别为:echo和async_echo),通过回调函数收到结果后进行展示。)

 客户端调用代码如下:

 1  rpc_client client;
 2   bool r = client.connect("127.0.0.1", 9000);
 3 
 4   for (size_t i = 0; i < 5; i++) {
 5     std::string test = "test" + std::to_string(i + 1);
 6     // set timeout 100ms
 7     client.async_call<100>(
 8         "async_echo",
 9         [](const asio::error_code &ec, string_view data) {
10           if (ec) {
11             std::cout << ec.value() << "async_echo timeout" << std::endl;
12             return;
13           }
14 
15           auto str = as<std::string>(data);
16           std::cout << "echo [async_echo]" << str << '\n';
17         },
18         test);
19 
20     std::string test1 = "test" + std::to_string(i + 2);
21     // zero means no timeout check, no param means using default timeout(5s)
22     client.async_call<0>(
23         "echo",
24         [](const asio::error_code &ec, string_view data) {
25           auto str = as<std::string>(data);
26           std::cout << "echo [echo]" << str << '\n';
27         },
28         test1);
29   }
30 
31   client.run();

22.使用CMAKE编译开源库

第一步,找到CMakeLists.txt文件,注意所在的文件夹。新建一个dir-build

第二步,打开cmake软件,我这里用的3.18.0,配置好源码路径、生成文件路径

第三步,在cmake软件,配置好所需的编译器。软件自动转换,将会生成以下内容

第四步,在cmake软件,点击“generate”按钮,再点击“open project”按钮,工程将自动用VS打开

 

 第五步,在VS点击构建,将会编译生成可执行文件

21.使用MQTT通信

前期需要第三方服务端,我选择了EMQ代理服务。主要使用浏览器打开 http://localhost:18083,能够看见连接、主题等等,方便测试

当前我推荐(依赖库)Qmqtt 。编译好了之后,直接在qtcreator中引用

win32:CONFIG(release, debug|release): LIBS += -L$$PWD/lib/ -lQt5Qmqtt
else:win32:CONFIG(debug, debug|release): LIBS += -L$$PWD/lib/ -lQt5Qmqttd
else:unix: LIBS += -L$$PWD/lib/ -lQt5Qmqtt

INCLUDEPATH += $$PWD/include
DEPENDPATH += $$PWD/include

代码示例:(连接信息仅需IP+端口即可)

    QMQTT::Client *client = new QMQTT::Client(QHostAddress::LocalHost, 1883);
    client->setClientId("lzw");
    client->setUsername("admin");
    client->setPassword("public");
    client->connectToHost();

注意一下Qos:

QOS0不可靠,因此适合大量数据的传输,因为很大量的数据,完全避免不丢包是很难的(网络环境、现实环境);

QOS1可靠,一般的场景够用,因为总能接到数据嘛。缺点就是 “可能造成” 一条数据,接收到了多次;

QOS2严格可靠,保证相同的消息只接收一条,耗性能。

20.使用Redis数据库

前期准备工作,需要下载解压Redis的Windows安装包。现在我们开始体验:

 当前我推荐(依赖库) acl-dev/acl。编译好了之后,直接在qtcreator中引用

INCLUDEPATH += Depends\include
LIBS += -L$$DESTDIR -llib_acl_cpp_d

代码示例:(连接信息仅需IP+端口即可)(这里加入键值对:test_key -  test_value)


#include "acl_cpp/lib_acl.hpp"
int run()
{
    // init socket module for windows
    acl::acl_cpp_init();

    const char* redis_addr = "127.0.0.1:6379";
    int conn_timeout = 10, rw_timeout = 10;

    // the redis client connection
    acl::redis_client conn(redis_addr, conn_timeout, rw_timeout);

    const char* key = "test_key";

    // test redis STRING command
    // bind redis_string command with redis connection
    acl::redis_string cmd_string(&conn);
    test_redis_string(cmd_string, key);

    // test redis KEY command with the same redis connection
    acl::redis_key cmd_key(&conn);
    test_redis_key(cmd_key, key);

    return 0;
}

19.了解一下memcpy_s,以便看懂他人代码

某个程序的稳定型,主要还是看代码逻辑,虽然有这些安全函数,但也不能过分依赖

    char in_src[10]{0}; char in_no = -1 * -1;
    in_src[in_no]= -100;

    int in_desLen = 9;
    char *in_des = new char[in_desLen];
    QByteArray in_checkValue = QByteArray::fromRawData(in_des, in_desLen);
    qDebug()<<in_checkValue.length();

    // in_desLen>=in_srcLen时,copy成功,返回值0
    // in_desLen<in_srcLen时,copy失败,整个数组赋值为0,返回值非0
    auto in_rlt = memcpy_s(in_des, in_desLen, in_src, 10);
    qDebug()<<in_rlt;

    in_checkValue = QByteArray::fromRawData(in_des, in_desLen);
    qDebug()<<in_checkValue.length();

18.使用深拷贝,更改对象所属权

/***************************************************************
* @brief        获取深拷贝对象,跨线程使用
* @date         2022-01-23
***************************************************************/
stuLog *TestHelper::GetCloneObj(stuLog *in_orgInfo)
{
    stuLog *in_newInfo = new stuLog();
    *in_newInfo = *in_orgInfo;
    return in_newInfo;
}

注意:所定义类中不能含有指针

17.使用线程安全队列,控制界面绘图速度

//模拟标识
int g_num = 1;

/***************************************************************
* @brief        模拟其他组件产生数据
* @date         2022-01-22
***************************************************************/
void TestHelper::RunExecWrite()
{
    while(1)
    {
        //if (g_num>50) break;

        stuLog in_info;
        in_info.id = g_num++;
        in_info.name = "hello www";

        this->AddData(in_info);
        QThread::msleep(20);
    }
}

/***************************************************************
* @brief        实际应用,其他组件传来数据
* @date         2022-01-22
***************************************************************/
void TestHelper::AddData(stuLog &in_data)
{
    bool in_rlt = m_queue->push(in_data);
    if (!in_rlt)
        qDebug()<<QDateTime::currentDateTime().toString("mm:ss.zzz")<<"AddData:"<<in_rlt<<" "<<in_data.id;
}

/***************************************************************
* @brief        实际应用,在界面上消费(避免界面卡顿,用户体验差)
* @date         2022-01-22
***************************************************************/
void TestHelper::RunExecRead()
{
    while(1)
    {
        QList<stuLog> in_list;

        if (m_queue->length()==0)
        {
            // 信号量阻塞,直到有新数据收到
            stuLog in_info; m_queue->pop(in_info);
            // 有新数据来了
            in_list.append(in_info);
        }

        for(qint32 in_idx=0; in_idx<m_queue->length(); ++in_idx)
        {
            stuLog in_info;
            bool in_rlt = m_queue->pop(in_info);
            if (in_rlt) in_list.append(in_info);
        }

        qDebug()<<QDateTime::currentDateTime().toString("mm:ss.zzz")<<"RunExecRead:"<<in_list.length();

        //SubData(in_list);

        QThread::msleep(200);
    }
}

16.kafka入门实践(默认需要安装java服务端)

客户端可以选择java,csharp,c++。支持跨平台,客户端上线数据回滚,毕竟是分布式持久化神器哈。

使用时,一般先创建一个主题,客户端(生产者)与客户端(消费者)通过主题进行通信。

它们之间的内部依赖关系如下。zkserver(java),kafka服务端(java),客户端(生产者),客户端(消费者)

可执行程序目录如下:

 关键代码如下:

1         static void Main(string[] args)
2         {
3             do
4             {
5                 Produce(GetKafkaBroker(), getTopicName());
6                 System.Threading.Thread.Sleep(3000);
7             } while (true);
8         }
1         static void Main(string[] args)
2         {
3             Consume(getKafkaBroker(), getTopicName());
4         }

15.C++实现类成员模板函数(自定义结构体)

入口统一,模拟接收了很多报文,都将进行数据预处理,最后再将结果统一输出,出口统一

void TestTemplate::PrintSomething(const QString &in_recvMsg)
{
    qDebug()<<in_recvMsg;

    TemplateA in_tplA; in_tplA.CarName = "LZW Car";
    HandleData<TemplateA>(&in_tplA);

    TemplateB in_tplB; in_tplB.PhoneName = "LZW Phone";
    HandleData<TemplateB>(&in_tplB);
}

template <typename T>
void TestTemplate::HandleData(T *in_info)
{
    QString in_rlt = "Nice";

    // 方式一
    if (std::is_same<T, TemplateA>::value)
    {
        TemplateA *in_tpA = (TemplateA*)(in_info);
        if (in_tpA)
        {
            qDebug()<<"CarName:"<<in_tpA->CarName;
            in_rlt.prepend(in_tpA->CarName);
        }
    }

    // 方式二
    QString in_className = typeid(in_info).name();
    if (in_className.contains("TemplateA"))
    {
        TemplateA *in_tpA = (TemplateA*)(in_info);
        if (in_tpA)
        {
            qDebug()<<"CarName:"<<in_tpA->CarName;
            in_rlt.prepend(in_tpA->CarName);
        }
    }
    else if (in_className.contains("TemplateB"))
    {
        auto in_tpB = (TemplateB*)(in_info);
        if (in_tpB) {
            qDebug()<<"PhoneName:"<<in_tpB->PhoneName;
            in_rlt.prepend(in_tpB->PhoneName);
        }
    }
}

template<typename T>
T TestTemplate::GetObj(const T &in_info)
{
    return in_info;
}

14.C++(qt)实现类似于CSharp的lambda查找(自定义结构体)

主要避免了写for循环,至于查找速度上,也快一点

//1
struct person
{
    QString name;
    int age;
    QString note;
    int cost;
    person()
    {

    }
    person(const QString &in_name, int in_age)
    {
        name = in_name;
        age = in_age;
    }
    //2
    bool operator == (const person &in_item)
    {
        return name.compare(in_item.name) == 0;
    }
};

/***************************************************************
* @brief        自定义结构体查找
* @date         2021-12-29
***************************************************************/
void FindDefineStuList()
{
    QList<person> in_list;
    in_list.append(person("lzw1", 18));
    in_list.append(person("lzw2", 19));
    in_list.append(person("lzw3", 20));

    // 找这个人的年龄?
    person in_objAm; in_objAm.name = "lzw2";
    QList<person>::iterator in_rlt = qFind(in_list.begin(), in_list.end(), in_objAm);
    if (in_rlt!=in_list.end())
    {
        qDebug()<<in_objAm.name<<":"<<in_rlt[0].age;
    }
}

13.使用zmq业务数据交互通信(请求-应答模式)与并行计算通信(任务-管道模式)

结合具体场景使用。

12.使用zmq轻巧业务应用通信(发布-订阅模式)

结合具体场景使用。大部分用于数据分发的场景

11.使用OSG-Earth玩转三维地图(离线加载)

主要效果如下,由于个人对c++宠爱多一点,所以就没玩 cesium.js,使用的传统的cs桌面软件形式

10.使用QMapcontrol体验轻量级的二维地图(离线加载)

由于直接依赖qt,所有用得简洁轻便,传统的cs桌面软件形式

9.快速输出C++结构体成员名与值,类型?

#include <iostream>
#include <string>
#include <typeinfo>

//获取变量的字面名字
#define Name(X) #X   
//打印变量的字面名字与值
#define ShowName(X) {std::string xname=Name(X); \
std::cout<<xname.substr(2,xname.size()-1)<<":"<<X<<std::endl; \
}  
//打印变量的类型
function {
int x=0; std::cout<<typeid(x).name()<<std::endl;
}

8.机器学习是选择tensorflow还是tensorflow lite了?

个人觉得还是结合实际场景进行选择。

TensorFlow 是谷歌开源的人工智能库,有最完善的生态支持,是进行人工智能领域开发和科研的必备工具。主要还是桌面端,linux居多

而TensorFlow Lite 是一种用于设备端推断的开源深度学习框架,同样也是跨平台。看了一下现在的桌面QQ也在使用了,注意保护个人隐私了。

7.基于QT插件系统,自定义开发业务框架?

//! ------>当前框架系统已集成 **********内部组件通信、外部进程通信、写日志、数据库ORM********** ! <------//

//! ------>近期将集成二维地图插件<------//

6.GIS,WGS84(世界通用坐标系)与GCJ02(火星坐标系)?

WGS-84 到 GCJ-02 的转换(即 GPS 加偏)算法是一个普通青年轻易无法接触到的“公开”的秘密。

目前可用于WGS84的共用地图,谷歌卫星地图、ArcGIS卫星地图和必应卫星地图

目前可用于GCJ02的共用地图,高德地图(互联网应用在本朝必须使用该坐标系)

1、高德地图:

【境内】:GCJ-02 WGS-84——>GCJ-02(高德有接口提供,反过来没有) 【境外】:暂不支持

AMap 就是高德地图,是高德地图在纳斯达克上市用的名字,主要面向互联网企业或个人提供免费API服务
MapABC 是高德集团底下的图盟公司,主要面向大众型企业或政府机关,并提供付费的有偿服务
Amap和MapABC,数据和服务都是共享的,所以Mapabc用Amap的API是正常的

2、百度地图

【境内(包括港澳台)】:BD09 在GCJ-02坐标系基础上再次加密 支持WGS-84、GCJ-02转换成BD09,反向不支持,并且批量转换一次有条数限制 【境外】:WGS-84

3、google地图

【境内】:GCJ-02 数据来源于高德,两者互通 【境外】:WGS-84

4、微软Bing地图:BingMap
【全球统一】:WGS-84

5、腾讯地图:SoSo地图
【境内】:GCJ02

坐标系知识回顾如下:

WGS84

WGS84坐标系是为GPS全球定位系统使用而建立的坐标系统,通过遍布世界的卫星观测站观测到的坐标建立,其初次WGS84的精度为1-2m。

瓦片z=0,x=0,y=0,对应的坐标范围是经度[-180,180],纬度[-85.05,85.05],对应的瓦片尺寸是256像素*246像素。

经纬度坐标(lng,lat)转瓦片坐标(tileX,tileY)的公式如下:

tileX=int( (lng+180)/360*2^z)

tileY=(1- arsinh(tan(lat*π/180))/π) *2^(z-1)

其中z是zoom level,计算结果取整数。

其中反双曲正弦函数arsinh(x),等价于ln(x+(x^2+1)^0.5)。

瓦片坐标(tileX,tileY)转经纬度坐标(lng,lat)公式如下(计算结果为该瓦片对应的最小经度和最大纬度)

lng=tileX/2^z * 360-180

lat=arctan(sinh(π*(1-2*tileY/2^z)))*180/π

其中,z是zoom level,双曲函数sinh(x)=(e^x-e^(-x))*0.5。

经纬度坐标(lng,lat)转像素坐标(pixelX,pixelY)公式如下

pixelX=(lng+180)/360*2^z*256%256

pixelY=(1-ln(tan(lat*π/180)+sec(lat*π/180))/(2*π))*2^z*256%256

公式中设定瓦片图块尺寸为256*256pixel,z是zoom level,web墨卡托平面坐标除以像素分辨率,再除以256取余就是像素坐标。

瓦片坐标(tileX,tileY)的像素坐标(pixelX,pixelY)转经纬度坐标(lng,lat)公式如下

lng=(tileX+pixelX/256)/2^z*360-180

lat=arctan(sinh(π-2*π*(tileY+pixelY/256)/2^z))*180/π

其中,z是zoom level。

GCJ02

GCJ-02是由中国国家测绘局(G表示Guojia国家,C表示Cehui测绘,J表示Ju局)制订的地理信息系统的坐标系统。凡是公开发布的商业互联网地图,一定要在此加密算法的基础上进行发布,这样一来地图的坐标就与实地的坐标不相符了,于是大家把这种坐标戏称为"火星坐标"。

5.GIS,小数点度 转 度分秒?

//12.2436°  -->  12°14'36″
QString convDecimaltoDMS(double in_dNum)
{
    //返回小于或等于指定数字的最大整数
    int in_dValue = (int)floor(in_dNum);
    double x = (in_dNum-in_dValue)*60;
    int in_mValue = (int)floor(x);
    double in_sValue = (x-in_mValue)*60;

    //返回结果,字符串格式化,不区分经纬,NE-SW
    QString in_ret = QString("%1°%2′%3″").arg(in_dValue)
            .arg(in_mValue, 2, 10, QChar('0'))
            .arg((int)in_sValue, 2, 10, QChar('0'));
    return in_ret;
}

4.根据业务需要,如何进行三表查询?

前提条件:股市数据表:tbStockMarket(主表),股票详情表:tbStockAttach,个人关注股票表:tbStockConcern

业务需要:查看最近个人关注的某只股票的股市价格走势,并带有股票信息

使用等值连接,SQL语句如下:

SELECT
A.ID, A.Name, A.Price, A.CurrentDate, B.Note, C.Grade
FROM tbStockMarket AS A
INNER JOIN tbStockAttach AS B ON (A.Code = B.Code)
INNER JOIN tbStockConcern AS C ON (C.Code = B.Code)
WHERE C.Code = '600039' ORDER BY A.CurrentDate

 成功执行该语句,符合预期

SQL知识回顾如下:

left join(左联接) 返回包括左表中的所有记录和右表中联结字段相等的记录 
right join(右联接) 返回包括右表中的所有记录和左表中联结字段相等的记录
inner join(等值连接) 只返回两个表中联结字段相等的行

3.QTreeWidget排序后,如何使每行序号不发生改变?

第一步:初始化首列为序号,并默认赋值

    QTreeWidgetItem *in_viewItem = new QTreeWidgetItem;
    in_viewItem->setData(0, 0, ++in_idx); //注释:in_idx是最初的默认排序

第二步:关联信号槽,排序后人工重置序号

connect(ui->tw_dataMarket->header(), &QHeaderView::sortIndicatorChanged,
            this, [=]() {
        for (int in_idx=0; in_idx<ui->tw_dataMarket->topLevelItemCount(); ++in_idx)
        {
            ui->tw_dataMarket->topLevelItem(in_idx)->setData(0,0,in_idx+1);

} });

效果如下:

2.win下面同一套代码,linux下编译成功后,竟然找不到同级目录的共享库?

  在项目工程pro文件下,加上RPATH命令:

  unix:!mac: QMAKE_LFLAGS += -Wl,--rpath=./

  执行qmake,重新构建即可

第一步:现象重现,找出哪个倒霉蛋

第二步:走回理想状态,破镜重圆

1.使用虚拟机之前还能和宿主机通信,后来突然就不行了,怎么回事?

  虚拟机指定的物理网卡和宿主机使用的物理网卡不一样,需要修改虚拟机的物理网卡后重新启动

第一步:关闭虚拟机操作系统

第二步:修改虚拟机的物理网卡,之后重新启动

第三步:打通任督二脉,状态回升

---------------->版本迭代中,最近更新日期:2023-04-29,五一快乐<----------------
---------------->版本迭代中,最近更新日期:2022-06-12,又是一年高考季<----------------
---------------->版本迭代中,最近更新日期:2022-11-12,双十一刚过<----------------
---------------->版本迭代中,最近更新日期:2023-03-04,离职待业<----------------

//! *****工作已稳定,目前就职于成都博宇利华。五年如一日,技术交流 -> qq邮箱 1358849798@qq.com,非诚勿扰***** !//


 
posted @ 2021-09-24 09:55  李涛贤贤  阅读(356)  评论(0编辑  收藏  举报