sqlite 到底是不是线程安全

背景

几个项目都用sqlite3,可能出现多个线程访问,项目自己加了锁,但我不知道到底sqlite到底是不是线程安全,于是网上搜索很多,都是翻译官方文档,具体也没有说清楚,于是今天自己搜索一下内容,不过搜索国外也没有很好解析,自己结合官网的文章和stackoverflow简单总结了一下。
下面以C++ SQLITE 来说明介绍

sqlite 线程安全设置

通过宏定义SQLITE_THREADSAFE是否线程安全,官方文档window与linux默认编译动态库是SQLITE_THREADSAFE = 1,代表线程安全,基本所有文档都这么说,但线程安全又分为3种模式,看这里就懵逼了,线程是否安全不就是加锁与不加锁,怎么还出现3种模式,我开始也不明白,后面看到官方介绍,自己细细分析区别就是加锁的程度不一样,因为SQL有很多函数,只是加锁函数个数不一样,比喻100个函数,如果模式0, 单线程那么就不用加锁,你都只有一个函数使用,这种场景其实也有,我就在主线程处理数据库操作,那么是不是就只有一个线程,那么有什么线程安全呢?所以100个函数都不进行加锁,感觉这个直接设置SQLITE_THREADSAFE = 0 不就可以了吗?但SQLITE 又提出这个概念,那么我在想可能一些底层访问还是加锁,只是我们用的API没有加锁而已(这里只是我猜测,没有看代码分析)

模式1 多线程模式,部分函数加锁,但一些函数不加锁,这种要一个线程一个连接,不能多个线程拿多个连接,可能出现线程竞争,这块具体哪些API,我目前还没有明白。

模式2 串行化模式,全部加锁,所以官方文档说这种没有限制的。默认采用这种模式

官方结论

https://www.sqlite.org/faq.html#q6

Threads are evil. Avoid them.

SQLite is threadsafe. We make this concession since many users choose to ignore the advice given in the previous paragraph. But in order to be thread-safe, SQLite must be compiled with the SQLITE_THREADSAFE preprocessor macro set to 1. Both the Windows and Linux precompiled binaries in the distribution are compiled this way. If you are unsure if the SQLite library you are linking against is compiled to be threadsafe you can call the sqlite3_threadsafe() interface to find out.

SQLite is threadsafe because it uses mutexes to serialize access to common data structures. However, the work of acquiring and releasing these mutexes will slow SQLite down slightly. Hence, if you do not need SQLite to be threadsafe, you should disable the mutexes for maximum performance. See the threading mode documentation for additional information.

Under Unix, you should not carry an open SQLite database across a fork() system call into the child process.

结论是线程安全,但必须要设置SQLITE_THREADSAFE=1,windows 与 linux 编译二进制文件默认设置thread-safe,
所以是线程安全,如果你考虑性能可以不要设置线程安全,因为这样子不用加锁,速度会快一些。但客户端又没有那么大高平凡需求,或者你只在一个线程使用,那么可以考虑使用非线程安全。

但这里设置线程安全,也要考虑线程模式,差别比较大,根据我上面思路,可以验证。

线程模式

https://www.sqlite.org/threadsafe.html

SQLite supports three different threading modes:

Single-thread. In this mode, all mutexes are disabled and SQLite is unsafe to use in more than a single thread at once.

Multi-thread. In this mode, SQLite can be safely used by multiple threads provided that no single database connection is used simultaneously in two or more threads.

Serialized. In serialized mode, SQLite can be safely used by multiple threads with no restriction.

The threading mode can be selected at compile-time (when the SQLite library is being compiled from source code) or at start-time (when the application that intends to use SQLite is initializing) or at run-time (when a new SQLite database connection is being created). Generally speaking, run-time overrides start-time and start-time overrides compile-time. Except, single-thread mode cannot be overridden once selected.

The default mode is serialized.

单线程模式

超过一个线程就是不安全,锁无效。

多线程模式

一个连接不能在多线程使用,因为一些函数不是安全,只是加锁颗粒变小,所以注意。具体官方文档有说明,看下面我会说

串行话模式

可以随便使用

线程模式官方更详细介绍

https://www.sqlite.org/c3ref/c_config_covering_index_scan.html#sqliteconfigsinglethread

SQLITE_CONFIG_SINGLETHREAD
There are no arguments to this option. This option sets the threading mode to Single-thread. In other words, it disables all mutexing and puts SQLite into a mode where it can only be used by a single thread. If SQLite is compiled with the SQLITE_THREADSAFE=0 compile-time option then it is not possible to change the threading mode from its default value of Single-thread and so sqlite3_config() will return SQLITE_ERROR if called with the SQLITE_CONFIG_SINGLETHREAD configuration option.

单线程模式:所有锁无效,如果你编译时候 SQLITE_THREADSAFE=0,就是默认这个模式,运行时候你无法动态改变线程模式,如果你设置就会报错。但如果线程安全那么是不是可以设置某个链接为了非线程安全(感觉可以)

SQLITE_CONFIG_MULTITHREAD
There are no arguments to this option. This option sets the threading mode to Multi-thread. In other words, it disables mutexing on database connection and prepared statement objects. The application is responsible for serializing access to database connections and prepared statements. But other mutexes are enabled so that SQLite will be safe to use in a multi-threaded environment as long as no two threads attempt to use the same database connection at the same time. If SQLite is compiled with the SQLITE_THREADSAFE=0 compile-time option then it is not possible to set the Multi-thread threading mode and sqlite3_config() will return SQLITE_ERROR if called with the SQLITE_CONFIG_MULTITHREAD configuration option.

设置多线程模式,数据库链接对象与预编译对象锁是关闭的,自己要保存链接与预编译是安全的。不能同一个时刻使用同一个链接,具体怎么不能使用,我暂时不能理解。。跟下面贴链接,大概就是同一个同时时刻执行不能执行冲突的语句。不然会竞争。
这里就有2种解决方案

  1. 队列【每个线程一个链接】,以任务形式丢到任务处理函数,这样子并发的。
  2. 线程池,每次拿到一个链接,执行完,放回连接池,这样子就不用管了,一定能保存,一个线程同一时刻使用到,主流还是连接池模式。
    这种多线程模式,性能比非安全低,因为部分有锁,但比串行又性能又好,毕竟并发的。如果对并发要求高,那么只能这种模式【客户端有这么多数据要处理吗?????我目前还是怀疑态度】

https://dev.yorhel.nl/doc/sqlaccess
貌似这篇文档有说一些解决方案

There are no arguments to this option. This option sets the threading mode to Serialized. In other words, this option enables all mutexes including the recursive mutexes on database connection and prepared statement objects. In this mode (which is the default when SQLite is compiled with SQLITE_THREADSAFE=1) the SQLite library will itself serialize access to database connections and prepared statements so that the application is free to use the same database connection or the same prepared statement in different threads at the same time. If SQLite is compiled with the SQLITE_THREADSAFE=0 compile-time option then it is not possible to set the Serialized threading mode and sqlite3_config() will return SQLITE_ERROR if called with the SQLITE_CONFIG_SERIALIZED configuration option.

可以放心在多个线程使用,给你锁的好好的,锁的颗粒最大。

查看线程模式

调用 sqlite3_threadsafe

我的总结

  1. 如果你设置SQLITE_THREADSAFE=1,并设置串行模式,那么就是线程安全的,默认windows与Linux官方的提供的包都是线程安全的。
  2. SQLITE_THREADSAFE = 1并设置多线程模式,必须保持同一时刻不能多线程处理同一个链接,所以解决方案是连接池,或者任务队列模式,来保存同一个时刻一个连接只由一个线程访问(我的理解,其实这个就不是线程安全,都要自己保存安全了,那还谈什么线程安全,我们常见线程安全就是直接调用,不要考虑不同线程),所以这种模式只是性能好一点,但线程安全还是由于把握。
  3. 串行模式,真正意义以上线程安全。你随便乱用都可以。
    模式只是锁的颗粒大小而已,但真正意义线程安全必须串行模式。大部分人就用串行就可以了,对并发要求高的就用多线程模式。如果只有一个线程使用的话,那么直接单线程模式(为什么要单独提出来就是因为默认线程安全模式,是有锁,所以必须你自己设置或者编译设置等等)

我这篇文章应该足够说明SQLITE 多线程问题了吧,感觉有的时候根本就不需要看代码,看代码反而更加搞不懂,因为别人的写的代码,不一定能映射到他的思维。直接看帮助文档和网上一些总结和自己开发经验就能推出来一些合理结论。。。。。

其他语言逻辑应该是一样的。。。。

noptead++ 替代品 sublime text

背景

之前写过类似的文章,前面用everyeidt 国产软件,我用了一个月样子,但还是不能接受临时文件搜索可能会出现错乱的bug,于是我换成sunlime text

sublime text 优势

  1. 漂亮,目前用过编辑器最漂亮的【vscode我认为不能算编辑器】
  2. 插件支持比较多
  3. 搜索比较强大,支持多种搜索条件【文件搜索】
  4. 带大部分编译命令,可能方便一键启动,但感觉这个功能不与直接集成控制台,类似vscode写法
  5. 语法识别,可以通过快捷键找到对应的方法
  6. 可以支持默认打开二进制文件,以16进制打开,如果只是简单复制16进制就只可以直接使用,如果不是以16禁止打开,可以在文件菜单以16进制打开。
  7. 右键可以快速打开文件所在的目录
  8. 各种命令组合,方便各种扩展,这个跟vscode有点类似

目前我自己认为优点

sublime text 缺点

  1. 收费,但试用一段时间,保存文件可能会出现提示,但后面我设置自动保存,这个就很少出现提示【问题不大】
  2. 普通搜索不会以文件搜索出现,普通搜索只能一步步搜索,默认不可以显示所有搜索结果,不过习惯就好了。
  3. 没有默认集成终端,这个可能我用vscode习惯了,觉得这样子非常方便,这个也可能用户自己直接终端,觉得没有意义。
  4. 没有右键打开文件菜单,必须自己手动添加
  5. 加载package 插件比较慢,因为是国外服务器

使用知识

插件packet 管理

  1. 打开选项
  2. 打开 Package Control
  3. 在弹出框输入install,会加载半天
  4. 找到你自己喜欢的插件,全部是英文

中文设置

按照上面包使用
如果有中文需要,需要在的packet管理搜索chinese

增加右键菜单

https://www.jianshu.com/p/eb9a263dccdc
但我以第二种方法,中文为乱码,我用一种方法,找到sublime text的默认设置,修改名字,然后输入对应中文就可以了。

这个同时可以手动删除右键菜单。

购买

官方购买要500多块钱,但通过淘宝购买团队版本大概只要100多块钱,貌似可以多台电脑使用,那么可以和几个小朋友一起购买一个就可以了。我自己买一个团队版本,不算白嫖。。。

总结

sublime text 应该算真正编辑器,他有点像vscode,感觉vscode有点借鉴,vscode 以electron js 扩展用js 开发非常方便,各种扩展包,再以微软官方支持,所以vscode发展非常快,同时vscode是ide与编辑器中间产物,所以带一定的ide属性,所以才有这么多人喜欢用。但相对于编辑器速度慢很多,所以作为开发来说还是要有一款编辑器用来常见编辑功能。

window 11 设置不要提示密码修改

问题

最近升级了win11最新升级包,又出现提示我修改密码,对于个人电脑不必要频繁修改密码,因为基本都是自己用的,而且我还是笔记本,基本只有自己能接触到,所以修改密码没有意义。

解决

  1. 打开Powershell,不是打开cmd(搜索powshell即可)
  2. 粘贴 Set-LocalUser -Name Administrator -PasswordNeverExpires 1
    -Name 接你的账号,如果你不是administrator,换成你自己账号名就可以了

    命令

    Set-LocalUser -Name Administrator -PasswordNeverExpires 1

总结

这个我找了好久才从网上找到有效的命令,不得不说window 10 以后好多功能都可以通过powershell来实现,以前命令慢慢被替换掉,感觉现在windows 更加接近开发的人群,可能普通人对电脑需求越来越低了吧。

自己开发手机协同软件支持多窗口了

背景

以前特别项目miui+的多窗口技术,觉得非常NB,自己研究好久总算开发出来了,其中遇到好多坑,还好自己都解决了。目前Scrcpy是不支持的,我可能是国内第一个真正支持的。我通过反射创建虚拟virtual display ,同时可以监听支持APP旋转。

效果图

斗鱼是单独app和一个主窗口,可以无限多个APP,只要手机支持的话,我自己测试跑到6APP,后面就没有测试了,miui+ 限制3个,可能怕手机性能不足导致问题。

总结

逆向miui+ 知道反射哪个函数,scrcpy 目前是不支持,等哪天我代码整理可以发布出来,目前含有太多测试代码和一些不规范代码。
win32开发界面感觉不是那么方便,当初就是为了体验一下以前开发界面的方式,不然直接就用duilib库去开发了。

虚拟display 有的APP不支持,但腾讯视频是支持,但miui+设置了黑名单里面,不知道为什么。

app名字获取,我目前通过解析应用宝,小米商店,库安解析获取的。分析半天发现读取资源太麻烦,看了半天绕来绕去的,感觉理论上应该可以解决,因为市面多开都是动态加载APK,反射资源类读取资源,只是app_process稍微不一样,更加底层,全部靠binder来操作,必须自己封装才可以。。。

socket io 初步了解(node js)

背景

公司的同事自己用socket io实现websocket服务,我用node js websocket去连接发现连接不上,于是我就找我同事。我同事说:必须要用socket io client连接才可以。我觉得很奇怪,一个weocket框架怎么还不能满足普通的实现,我说你是不是代码写错了,后面发现是我理解错了,我同事也理解错了,我们当初定义协议走websocket 通信,协议就直接走json 或者其他自定义协议即可。

自己花了半天时间看帮助文档和代码开发

分析过程

  1. 直接分析源代码调试
  2. 看官方的帮助文档,全部看完

socket io 到底是什么?

socket io是一个网络通信框架,依赖websocekt,并没有实现websocket,对应业务层逻辑,跟我们自己依赖系统套接字(tcp协议)实现自定义协议是业务层一样。如果我们用websocket实现自定义协议,别人用websocket必须按照我们定自定义协议通信,所以socket io 服务,不能用原生的websocket连接,我自己用127.0.0.1:3000/socket.io/?transport=websocket&EIO=4 虽然可以建立的链接,但发送消息就立即断开,因为包的格式不对。
它定义协议包,我们只要emit 提交包就可以了,我们可以给基本类型,或者给对象或者Buffer(二进制数据),基本就不用管协议了。

socket io 几个我用到特性

emit 投递数据包

//客户端监听
socket.emit("hello", { a: "b", c: [] });

//服务监听hello 消息
server.io.on("hello", (a,b,c)=>{

})

这个因为自定义协议,所以包的定义就不要了,投递内容就可以了。
纯websocket 不能emit 投递数据,不是给网络使用的,所以这个特性用起来就特别舒服,减少一些工作量。
不然我们就要在服务器端 在onmessage 来自己解释数据包了,那么就要定义id字段,来判断是什么类型的。具体包的协议我没有研究,如果自己就用二进制来传递,解包就必须一个一个写。socket io 能判断传递类型,那么说明就是在网络协议里面传了类型,不然无法知道什么类型。

身份验证

客户端在连接时候可以给socket auth复制,比喻传递一个对象{token: "验证密钥"},也可以传递函数,用函数的返回值灵活获取。
如果你token有过期时间,那么建议传递函数,因为要更新token.
官方的例子

import { io } from "socket.io-client";

const socket = io("ws://example.com/my-namespace", {
  reconnectionDelayMax: 10000,
  auth: {
    token: "123"
  },
  query: {
    "my-key": "my-value"
  }
});

重连

如果服务器重启,或者客户端断网,那么socket io 自己会进行重连。如果服务器主动disconnet的话是不会进行重连的。
重连得到时候默认传递之前给的token,如果token有更新就校验失败(如果过期的话),所以还是建议传递函数。

request-respond的模式支持 类似http request- respond 一一对应

你可以提交一个包,最后一个参数是一个函数话,服务器会通过通过回调函数传递参数(肯定不真调用回调,看起来像而已,2个跨网络 怎么可能直接调用呢,这个就点像ipc)

socket.emit("task1",data,call_back);

原理

创建任务id跟你数据包一起传递给服务器,但服务器会传送数据也会带上这个任务ID,但检测有任务id进行比对,找到当初回调函数,调用即可。 一些好多网络库也是这么开发的 ,通过任务ID实现。
http 半双工,只能一问一答(协议决定),http 发送请求后就一直等待结果,结果无法访问时候,可能不能发送内容(http 1.1)http 2.0 我就不知道了,如果实现全双工的话,估计也是通过类似task id逻辑是实现

socket io 实现回调代码

    /**
     * Called upon a server acknowlegement.
     *
     * @param packet
     * @private
     */
    onack(packet) {
        const ack = this.acks[packet.id];
        if ("function" === typeof ack) {
            debug("calling ack %s with %j", packet.id, packet.data);
            ack.apply(this, packet.data);
            delete this.acks[packet.id];
        }
        else {
            debug("bad ack %s", packet.id);
        }
    }

            //emit(ev, ...args)
            //最后一个参数如果函数,创建packet,服务器响应时候,传送回来即可
            //这样子就可以变成Http
            if ("function" === typeof args[args.length - 1]) {
            const id = this.ids++;
            debug("emitting packet with ack id %d", id);
            const ack = args.pop();
            this._registerAckCallback(id, ack);
            packet.id = id;
        }

room的概念

我没有写,但以后用到,这样子方便对用户进行过滤,这个业务方便对用户进行快速操作而已,不用自己进行for循环遍历比较了

不支持websocket会用http 轮训模式

默认就是轮询,所以建议直接设置transport 为 ['websocket', 'polling'] 2个服务器。但我没有测试,如果开始用轮询是否会升级到websocket,没有验证这个需求。

socket io 简单总结

socket io 是一个网络框架,封装一些业务功能,所以你不能用纯websocket连接,具备验证,重连,房间,自动解包特性,加快业务开发能力。市面太多用来聊天软件,我觉得主要原因是浏览器兼容性,他可以一套代码兼容所有浏览器能力(可以在不支持websocket浏览器跑),因为聊天网页不知道用户在什么浏览器上,但我感觉这个特性在未来会越来越弱,因为浏览器版本升级,win7 等系统份额越来越少,那么以后系统浏览器标准化,感觉这个框架就比较弱了,因为稍微有实力公司自己在websocket 写一套业务很简单,不过在socket io 上二次开发也简单。


现在互联网是一个好的时代,什么业务都基本对应的开源代码,什么东西都参考,除了小部分高端或者底层东西没有。对于小公司来说太方便了,开发速度嘎嘎的。

感谢那些为开源做出贡献的那些人

pecompact 压缩壳脱壳初探

背景

一个朋友找我脱壳,不过我从来没有脱壳,于是我研究了一下pecompact脱壳。

网上知识

https://blog.51cto.com/u_15076212/3690173

自己过程

  1. 我按照网上知识走
  2. 按照他方法脱,发现不能用
  3. 我x86dbg 分析,发现地址不能访问,我发现重定位表没有修改
    我后面发现脱壳,都需要修复重定位表
  4. 我搜索这个有关知识,要么就修复重定表,要么就设置程序不要动态基地址。
  5. 我用studype+设置固定地址
  6. 网上有修复重定位表脚本,本来想有时间自己写一个小软件修复重定位表的,但感觉以后基本没有时间研究这个,毕竟好玩的东西太多。。

    总结

  7. pecompact 用SEH,触发修改代码
  8. 加壳就是动态加载pe那套技术
  9. 可以用在virtualalloc 下断点,基本能够很快找到oep
  10. 单点跟,我用x86dbg很容易出现跑飞,异常情况,我开始因为壳导致,后面发现知识x64dbg软件问题,所以直接在后面加断点。
  11. 压缩壳,内存里面真正有PE,所以直接dump,修改PE入口点,导出即可。
  12. 如果打补丁,感觉不一定要脱壳,可以在写dll注入程序,等动态加载成功,然后再修改内存的代码,这样子壳兼容性就基本不用考虑了。

压缩壳为了压缩,并不是为了加密,可能加大破解地方。

其他脱壳资料

https://www.dounaite.com/article/62cdcc63f4ab41be487a5715.html
https://www.anquanke.com/post/id/99750

说明

这篇文章只是自己第一次脱壳,遇到一些问题,怎么思考,怎么解决问题过程。写这篇文章只是为了记录自己技术点滴而已,用于优化自己思考方式而已。

miui+ 协同软件 多窗口技术研究

背景

miui+ beta 软件貌似出来蛮久了,这个技术原理和scrcpy差不多,只是miui+ beta是系统软件,所以他可以直接反射,而不需要开发者权限才能反射。

优点

  1. 支持最多3个独立窗口【APP 独立窗口,不会在手机物理屏幕显示】
    不过一些程序屏蔽多个窗口,比喻腾讯视频就不可以,貌似不是技术原因,因为一些斗鱼,虎牙视频类可以开启独立窗口,我用JB逆向分析看他是写了包名做过滤而已,
  2. 复制程序比较方便
  3. 不用蓝牙就可以传递声音
  4. 不用开启开发者模式
    编码声音传递

    缺点

  5. 每次连接基本都要扫码,很容易连接不上,这点我是非常不能理解,我是小米笔记本,这么大一个公司,基本功能做的非常不稳定,所以他的beta 一直没有去掉。貌似起码都出来一年多,产品还这么不稳定,这个点我实在想不明白,我不知道小米投入多少开发,但感觉不应该,一个扫码总是出不来,PC 没有技术兼容性,本身就是只是渲染层,如果考虑其他平台的话,PC端都做不好,其他有什么用呢???
  6. 不能像scrpcpy类产品直接黑屏,miui+ 只是不锁屏,屏幕还是或多或少亮着,可能考虑安全考虑,但只是wifi能连接,我觉得这个问题不是很大,但有通知提醒,可以一键点击退出,所以安全考虑有点站不住脚。大不了加一个开关,默认关闭,只有需要协同必须手动开启即可。
  7. 连接必须开启gps定位,这个是我不能忍的功能点,如果安全考虑,为什么要定位呢?难道手机定位移动超过一定范围就停掉吗?但不是只能wifi吗?安全也可以加默认开关,开启gps就会耗电,用一些程序就会获取实时定位,但有的时候并不像开启定位。
  8. 最新版本不能设置右键快捷,因为我希望返回右键。
  9. 不能走usb传输数据,必须开启wifi

    miui+ 总结

    miui+ 用起来还可以,只能说够用,现在改名小米妙传,Miui+ beta 官方不提供现在,酷安有人提供小米妙传的地址, https://www.aliyundrive.com/s/teDgZazeWU5
    安装包会检测机型,可以在cmd 拖入安装包,然后增加参数 /i 就可以自动按照。安装后删除miui+ 前一个版本。
    目前用自己的协同软件非常舒服,感觉速度比alink和 miui+速度要快一点,我不知道为什么,难道是c++ 性能就是快吗?
    自己

我自己的win32+ffmepg api+sdl开发。

miui+ 多窗口技术

我一次用窗口,这样子手机可以同时跑几个APP,好处有什么用,我可以一边看视频,一边微信回复,可以不用小窗口,因为我都用PC,我窗口已经非常大了,我可以放几个窗口。

过程

我要探索这个技术,那么就有逆向miui+ apk

  1. 我搜索miui+ apk,网上找到一些版本
  2. 用jadx逆向分析
  3. 具体代码在display, mirror 包下面

创建窗口逻辑

  1. 创建virtualdisplay
  2. 创建成功然后启动指定APP【指定display id】
  3. 模拟点击和按键要指定display id
    如果不指定display id,那么就是默认物理屏幕去了。

技术验证

用最简单代码验证这个逻辑

  1. 开启手机模拟辅助显示设备【开发者模式】
  2. 用adb命令找到这个窗口display
    dumpsys window displays
    找到非0 那个 Display: mDisplayId=57 rootTasks=1
    我找到57,你的可能大于0任意一个数字
  3. 写代码启动知乎到57

    PackageManager packageManager = getPackageManager();
        String packname = "com.zhihu.android";
        Intent intent = packageManager.getLaunchIntentForPackage(packname);
    
        Bundle opts=ActivityOptions
                .makeBasic()
                .setLaunchDisplayId(57)
                .toBundle();
    
        startActivity(intent, opts);

    这里注意android 是12的话要设置权限获取知乎权限,可以另外代码方式启动知乎。packageManager.getLaunchIntentForPackage(packname); 这个 android 12需要权限。

  4. 效果图

可以看到副窗口显示知乎,主窗口是没有改变。这个功能有点像小窗口功能,说不定这个技术就是这个原理。

总结

后续我会在自己的写的协同软件增加窗口功能,自己开发软件想加什么功能就加上什么功能。别人写的软件或者功能很难满足自己的需求。

Miui+ 开发者,我感觉他们开发者自己都不怎么用这个产品,做技术的人,应该多用自己开发产品,同时用同类产品。否则很难知道什么是好,是什么是坏。可能小米发展太快,估计只是周边产品,没有投入太多精力。

jsoncpp json压缩转换字符串写法

背景

自己用jsoncpp已经几年了,一直都用 toStyledString来转换字符串,但这种格式化字符串,但如果用来传递数据,那么有许多多余数据,所以我一直想找到压缩的字符串,网上找了一些关键词基本都没有找到,突然有一天我直接看一下jsoncpp的源代码。

过程

  1. 查看toStyledString 代码
    
    std::string 
    Value::toStyledString() const
    {
    StyledWriter writer;
    return writer.write( *this );
    }
题外话:用vscode看代码还是蛮舒服的
jsoncpp 定义styledWriter ,然后我发现他有一个FastWriter

class JSON_API FastWriter : public Writer
{
public:
FastWriter();
virtual ~FastWriter(){}
void enableYAMLCompatibility();
public:
virtual std::string write( const Value &root );
private:
void writeValue( const Value &value );

  std::string document_;
  bool yamlCompatiblityEnabled_;

};

然后看了一下write就是我想要的压缩的字符串。

## 使用

Json::Value root;
root["id"] = "test";
root["name"] = "fish";
FastWriter fast_writer;
std::string result = fast_writer.write(root);


## 总结
jsoncpp 我用几年前的老版本,看github 貌似重写了,不过目前自己够用,新不代表就好。。
jsoncpp 我的用版本不支持 uint_64,我只能用std::string 来代替

vs2019 c++开发软件独运行[运行库文件抽取]

背景

用vs2019 c++开发软件,发行版本需要运行库,因为别的电脑不一定安装运行库,所以要特别处理

方案

  1. 编译的exe,c++运行库设置MT(静态模式),代码集成在你的exe中
    1. 导致exe变大
    2. 其他第三方库可能冲突【可能第三方库需要改变编译模式】,常见冲突在这里
    3. 存在多份运行库代码,增大安装包体积
    4. 简单
  2. 需要动态库DLL 放在exe执行目录
    1. 需要复制多个DLL,所以要知道依赖哪些库
  3. 安装运行库
    1. 增加安装包体积
    2. 安装运行库万一冲突,还可能失败【对于阉割系统,太多麻烦的事情】
    3. 增加安装时间

      选择

      主流方案都选择第二种

      常见需要复制文件,打开vs2019,然后跳出任务管理器,找到对应进程,然后打开所在的目录


目录跳到IDE这一层

进行搜索
vcruntime140.dll
msvcp140.dll
ucrtbase.dll
api-ms-win-crt-conio-l1-1-0.dll 打开这个位置所有api-全部复制出来,懒得一个一个找。

基本大部分项目足够,如果软件还报错,他会提示,你自己慢慢复制就可以了,其他的版本vs也是这么慢慢查找。

备注

一定要放在exe同级目录,因为window搜索动态目录是这样子(非系统DLL优先级是当前目录最大)。
vs2019 多了好多api,貌似2015以后微软优化运行库,我看了一下文档,没有看出什么特别的地方,现在只记得它进行优化。。。

POCO c++ 库 string to utf8 string

背景

POCO 是一款全面的c++开发框架,基本设计大部分常见使用功能,但没有直接std::string to utf8 string代码,网上找了好久找到(有Unicode std::wstring 转换utf8 std::string)

代码

Poco::Windows936Encoding cp936;
Poco::UTF8Encoding utf8;
Poco::TextConverter converter(cp936, utf8);
std::string src = "你好";
std::string dst;
converter.convert(src, dst);

说明

Windows936Encoding 包含gbk,所以可以用来转换中文到utf8 std::string, 这个东西我是从github 上找到有关的问题,所以记录一下,方便窄字节字符串转换成utf8编码。主要还是c++ 基础库太不够用了,学术太重,不够落地,导致c++ 一个好用的网络库都要用第三方的,或者自己封装。对于自己开发,什么都要自己,对新手太不够友好了,所以建议c++ 用通用第三方库,加快开发速度,降低门槛。或者换其他的语言,没有必要浪费时间在一些跟产品没有关系的东西上。因为语言就是为了解决某种需求,而不是为了编程而编程。