我的像素编辑器马上就可以上线steam了,商店和应用的审核都过了,就等一到时间就发布了。 这个应用做的我还是挺头大的,因为基本没有做过比较大的成品的桌面工具,而且还是跨平台的。里面涉及很多技术问题之前都没有接触过,走了很多弯路,折腾消耗了很长的时间。不过现在回头看,倒也还好,正常的学习折腾阶段。可能目前还有bug。 软件功能属于基本的不能再基本的了,后面还好持续更新迭代。目前只实现了颜料板,工具栏,图层等基本功能。动画的帧没有实现,后期实现这个功能,需要捋一下帧跟图层的关系。这个现在还是脑子空白状态,说实话这种情况实现软件,在设计上不太合理,后面加帧的功能有可能需要大改代码结构。还有很多有意思的功能,比如笔刷,还有一些性能优化要做。还有一些基本的,比如快捷键映射,保存目录等一系列小功能。 技术上,其实做这个的初衷有一部分是为了实现游戏框架,因为我发现这东西跟游戏逻辑一模一样。游戏引擎完全通用。所以实现上我直接从底层写的引擎的相关逻辑,没用当前的一些游戏引擎。比如,我选择直接从opengl开始撸,说到opengl,这个我也断断续续学了好几次了,在这个编辑器场景下,我opengl的方案修改了三次方案,只为性能更好,现在也觉得有优化空间,还有几个优化的想法,但是得需要性能测试。 ui用了imgui,挺不错的一个库。完全可以深度定制,属于我的引擎的一部分了。完全可以在之后的游戏或者软件开发里继续用。说到ui,让我想起了这个软件编程语言的选择,本来开始想的是用纯c撸,但是后来发现c的库太少了。比如ui这里觉得imgui很好,最终觉得用他。就决定直接改c++的项目,但是里面代码还是一部分c一部分c++, c++基本只用到namespace和调库使用,还有一个std 库。std库提供的基本数据结构,能减少c的很多手撸代码的情况,算是特别方便了。 然后后来渐渐的,由于软件场景的需要,使用的c++的面向对象的功能越来越多。包括后来考虑跨平台的问题,升级到c++17的标准,看了很多cppreference的文档。觉得c++17甚至20提供了很多的新语法,不比现代语言差。慢慢的基本写的时候,都用c++的库,包括写法。尽量不写c,发现c++确实有很多优点(虽然现在很多c++高级功能还没用到)。让我再一次放下对语言的偏见。 觉得c++兼容的c的标准,属于成也萧何败萧何了。但是如果能尽量保持c++的风格,就也很好了。 其他的三方库用的很少,刚加入了psdlog作为文件日志的选择,刚开始封装了一个标准输出的日志代码,现在也用不上了,约等于白写。 编辑器支持psd文件的读写,使用的三方库,但是我也改了一些问题,当时挺头疼的。 还有一个很大的问题是国际化的问题,刚开始考虑复杂了,以为要通过操作系统的语言去切换软件的语言,后来steam官方说的是通过steam控制的。我刚开始选择了gettext这种老牌库,然后就坑了。在mac上,locale完全设置不了,但是自己启动时没问题的,通过steam启动,locale失效,设置也不生效。而且windows上没问题。为了解决这个问题,我本来想上icu4c这个库,因为这个库还能解决编码的问题,一举两得。但是感觉要改的地方有点多,最后手撸了个代码,自己实现了一个gettext。至于编码兼容的问题,目前适用大部分情况就可以了。后面再改的时候还是要用icu这个库。 说到跨平台和编码问题,确实c++这种语言,跨平台的问题太大了,包括代码和第三方库的编译,gettext我刚开始在windows上折腾,用的源码编译静态库,后来用的系统自带的。现在也用不上了。因为用camke管理的代码编译,windows下我用的mingw编译环境,这个也折腾了好几天。开始装了win7,想多兼容几个系统版本。库的链接一直不通过,我以为是版本问题,升级了版本,发现直接不能用了。后来升级win8.1发现一样的问题。然后才知道是库链接配置的问题。 这个软件,看似功能不多,但是细节做起来还是挺复杂的。除了上面这些不了解工具链或者系统环境等导致的问题,还有直接技术实现的盲区。我印象最深的而且很简单的场景是:刚开始实现完画布和画笔的时候,感觉很开心,那时候觉得这个软件至少实现百分之七八十的功能了。其实现在看来可能百分之十。然后我用画笔乱画的时候,发现一个问题,鼠标移动过快的时候,其实系统能检测到的根本不是连续的点,我的想法有点想当然了。这就涉及一个问题,线的补齐,而且还需要怎么样补齐的合理,这个是关键。刚开始是懵逼的,后来查了很多资料,发现针对问题的想法还是很重要的。 最后还得感慨一下,我这个steam坑位本来是要留给游戏的,现在变成像素编辑器了。倒是可以为以后的开发做技术积累和框架提前实现。只是我一直在想的问题,现在不准备从底层撸框架实现游戏了。现在看看使用JavaScript写了,这个引擎暂时在这个游戏上用不到了。只是因为JavaScript的跨平台能力,小程序之类的,webgl/webassembly这种的还是目前不是主流,肯定折腾的东西太多。学技术可以折腾底层,搞项目还是快速的框架比较好。

Continue

今天接触了js的两个工具,一个是nodejs的版本管理工具nvm 一个是nrm,配置npm的镜像源管理工具。

Continue

之前自己手动和使用ubuntu自带的附加驱动安装,每次都失败,然后只能进bash删除重新安装。我记得之前启动时有错误提示。 现在就没想通过自带的安装了。今天手动安装完,启动直接卡死,通过搜索有篇文章说的,需要bios改为使用独立显卡。 然后我就才知道Discrete Graphics 为独立网卡,graphics device为集成显卡。进过很多次bios看到过,但是我认为的正好相反。 改完之后然后就正常启动,感觉图片色彩好像都更鲜艳了。流畅度到没有太大区别。

Continue

因为用到xdp相关的东西,centos7操作系统的内核版本为3.10,准备编译升级一下。还从来没有手动编译安装过。 看了官方文档,没有啥特别流程,讲了一些注意事项。我按照网上的步骤来的。 下载内核: curl -O https://cdn.kernel.org/pub/linux/kernel/v4.x/linux-4.19.230.tar.xz 解压: tar xf linux-4.19.230.tar.xz 然后,把之前内核编译配置复制过来: cd linux-4.19.230 && make mrproper, cp /boot/config-3.10.0-1160.53.1.el7.x86_64 ../.config 进行配置:make menuconfig,看文档应该是make oldconfig,可能用这个读的.config文件吧。 配置没太敢改,只改了Processor type and features —> Processor family (Core 2/newer Xeon) 选了newer Xeon。这个我还翘"?"看了一下介绍,可以cat /proc/cpuinfo,看看cpu family, 6为new,15为old。 编译: make -j 32 安装:make modules_install && make install 配置启动: 查看当前启动选择:grub2-editenv list 设置默认第一个启动:grub2-set-default 0 确认设置:grub2-editenv list,这里我在/boot/目录下找了一下grub.cfg配置,第一行确实是刚安装的内核版本。 重启:reboot 重启没有什么问题,安全起来了。 还有几个编译依赖文件,之前我对照官方文档检查了几个主要的,但是有些需要devel版本的,起始发现没装还是得重新安装。 yum install ncurses-devel.x86_64 elfutils-libelf-devel openssl-devel 没啥难度,毕竟也算世界上最大的开源项目了吧,应该做的很容易。最难的是内核定制,完全不知道应该怎么选择,选择哪些配置能提升性能,不然本地编译的还比不上版本分发带的普适版本的性能好。

Continue

FinalizeRunMode,检查了一下daemon和运行的模式是否匹配,然后模式保存到全局变量run_mode中。 StartInternalRunMode,这个是判断是否是一些打印相关的模式,如果是这些模式,调用相关的方法,这些方法就不看了。比如列出模式,打印软件帮助等这类的模式。 GlobalsInitPreConfig,先调用TimeInit,初始化了一个当前时间的自旋锁current_time_spinlock,具体干啥的还不知道,调用tzset设置时区变量。之后调用SupportFastPatternForSigMatchTypes,初始化sm_fp_support_smlist_list,是个链表,默认保存了DETECT_SM_LIST_PMATCH,优先级为3,具体不知道这个是干啥的。之后调用SCThresholdConfGlobalInit,我看主要是初始化了解析Thresholding的正则表达式。 LoadYamlConfig,加载配置文件,调用ConfYamlLoadFile,这个里边主要利用了yaml库解析配置文件,没查这个库具体函数,函数名很容易知道是干啥的。保存了一下配置文件的目录,主要是调用ConfYamlParse,把配置读入ConfNode结构的树里边,有父节点,然后是个链表。所以也不单纯是个树。没太仔细看具体解析流程,单纯就是读到树里了。 typedef struct ConfNode_ { char *name; char *val; int is_seq; /**< Flag that sets this nodes value as final. */ int final; struct ConfNode_ *parent; TAILQ_HEAD(, ConfNode_) head; TAILQ_ENTRY(ConfNode_) next; } ConfNode; ConfDump模式单纯就是把刚读如的链表树再打印一下。 查了一下“vlan.use-for-tracking”的值,这个参数看了一下配置文件介绍,基本用不到。 ConfGetBool获取配置中的bool值,先调用ConfGetValue获取值,里面通过ConfGetNode通过name找到node,key通过“.”进行分割,然后ConfNodeLookupChild查找当前等级的链表。看到这里发现,用c实现个json解析啥的好像也不太难啊。 SetupUserMode(&suricata);这个是设置非system模式的情况下,把日志和数据目录设置到当前目录,函数没跟进取,暂时不看了,这些模式不是看的重点。 SCLogLoadConfig应该是设置日志了,通过verbose设置等级,verbose通过参数有几个v来设置,等级为SC_LOG_NOTICE + verbose,看了一下SCLogLevel, 最高可以有5个v。获取logging.outputs的配置保存到outputs,SCLogAllocLogInitData初始化SCLogInitData,这个数据结构主要保存日志等级,格式,写到什么地方等信息。获取配置文件里"logging.default-log-level"配置的日志等级,然后跟参数里的比较,取等级最低的,保存到global_log_level。如果等级跟配置文件一致,使用配置文件的format。将outputs配置文件保存到变量,这些主要是日志的方式,console/file/syslog,没有细看,看了一下file的,这个用的多,调用SCLogInitFileOPIface,append模式打开文件,方式里面有个锁变量,注释说用来切割日志时候用的,然后调用OutputRegisterFileRotationFlag,把需要分割日志的这个flag都保存到output_file_rotation_flags里了,这个也是个链表。这里暂时有个疑问,我看flag初始化的时候没设置值,不知道后面会不会设置,还是我漏了。这里保存的是指针,可能不是漏了。日志等级还比较了outputs里的等级,取最低等级。然后调用SCLogInitLogModule,这个在之前调用过,之前可能是终端输出,现在可以配置文件了。 LogVersion,打印版本。 UtilCpuPrintSummary,打印cpu个数信息。 ParseInterfacesList,这里是看启动参数是否设置网口,如果设置会在配置里加一个xxx.live-interface的配置项,没设置就调用LiveBuildDeviceList,参数是模式,也是配置文件里的顶级名称,使用这个参数获取配置,如果interface为default,则忽略,这个是默认配置,其他情况调用LiveRegisterDeviceName,把接口插入队列,这个跟参数解析一致。所以看起来好像启动参数不加网口也可以啊。

Continue

SuricataMain是入口函数,先调用SCInstanceInit,把SCInstance变量数据清0,不知道为啥以及memset0了,还要变量名再置0一次。SCInstance就是suricata进程相关的一些变量,其中一个有意思的事是还保存了执行命令的文件名,看这个感觉可能直接改二进制的名也没问题的。run_mode设置为RUNMODE_UNKNOWN。 之后调用InitGlobal,主要设置suricata_context变量,这个变量在rust-context.h文件定义,全是操作函数,具体赋值的函数还没有看,这个先过了。 在InitGlobal里调用rs_init,这个看了一下好像是给rust调用用的,sc赋值给rust里的sc,这样在rust里可能就能试用context的函数了,我看在core.rs中都是contxt里的函数声明。具体c和rust怎么交互的,我还需要再看看。粗略看了一下,协议判断好像都在rust里写的。 然后初始化engine_stage为0,这个变量为原子变量,原子操作都定义在util-atomic.h,没细看怎么实现的,先知道干啥的吧。这个变量注释说的是表明引擎是在初始化还是在处理数据包了,总共包括三个状态SURICATA_INIT,SURICATA_RUNTIME and SURICATA_FINALIZE。 SCLogInitLogModule,初始化日志模块。没细看,参数传的NULL,使用默认日志系统。info等级打印到console,可以设置正则过滤,这几个设置项都可以通过环境变量设置。 之后ParseSizeInit,初始化了一个正则匹配器parse_regex,这个正则表达式不知道干啥的,看后面好像是把字符串“10kB,10GB”类似的转换成具体的大小数据,可能是配置文件之类的解析,先过了。 之后RunModeRegisterRunModes,跟函数名一个意思,注册的模块还没看。看配置文件就知道四五种,没想到还挺多。注册到数组runmodes。找了几个看看,发现就是list-runmodes里的模式,把对应的模式和具体模式的方法进行注册。每种模式都是调用RunModeRegisterNewRunMode注册到runmodes数组保存。RunModeFunc是对应的模式函数,这个先没看,等用到再看 之后ConfInit,初始化配置模块,ConfNode是一个列表,里面是kv键值对。起始就是初始化一个链表。 到这InitGlobal就结束了。 ParseCommandLine解析命令行参数,列出了所有参数,pfring或pfring-int参数启动pfring,设置run_mode为RUNMODE_PFRING, 如果后面跟参数,设置pcap_dev,这个应该是网口名了。LiveRegisterDeviceName就是把网口插入到一个链表里,相当于注册了。变量名pre_live_devices。capture-plugin还能设置插件名,这个模式RUNMODE_PLUGIN,可能dpdk得插件实现。netmap参数只能设置一次,看来只能在一个网口使用,而且还不能多个模式。 suricata --list-app-layer-protos 列出七层协议 suricata --list-runmodes 列出模式 list-keywords 关键字 -l设置日志目录 -i和af-packet都走af-packet,-i如果支持,默认也走af-packet。 这些参数在help里都有,暂时不看了,到时候回来看具体设置了什么参数,因为我看的代码比较新,之前版本的还有没有的参数。

Continue

今天折腾了一天的ubuntu系统,先是18.04对于为这个电脑好多硬件不支持,声音,GPU都不行。决定升级20.04,20.04支持硬件驱动,但是从18.04到20.04升级太曲折了,升级完系统,wifi和声音都有问题,导致进不了系统,刚开始为切换到shell,禁止加载mod也是不行。 最后竟然发现进入恢复模式后,再切换到正常启动就能进入桌面了。恢复模式也提示了,桌面环境有的可能需要正常启动才能使用。为这个可能没正常启动,导致一些检测跳过了吧。后来装显卡驱动,升级了内核版本,然后突然间就好了。不知道为啥升级系统的版本的时候不给我直接升级内核版本。 哦对,不正常启动的时候,竟然cpu不太高,风扇呼呼转,不知道咋回事。正常了后也正常了。日志里的报错也没啥用,直到是wifi和声音mod的问题,但是没办法解决。 正常后的20.04的界面还挺好用,很流畅,也比之前好看多了。 开始界面调整外观风格没有变化,后来发现需要升级一下桌面,apt install ubuntu-desktop就可以了。 sudo lspci | grep -i nvidia 这个命令查看显卡信息的时候,因为没有显示,网上找了一个网站能通过id查询。 http://pci-ids.ucw.cz/mods/PC/10de?action=help?help=pci url里的id是供应商id 再后来,帖子看多了,发现可以直接升级本地pci数据库。看来这电脑还真是硬件配置新啊。 sudo update-pciids 显卡驱动最后也没安装成功,懒得折腾了,暂时也用不到显卡的特殊功能,先这样吧。

Continue

最近又在写ansible相关的东西,因为得集成python项目,我开始都想之间命令方式调用ansible了。因为之前搞了好几个版本的ansible集成,每次都是大折腾一段时间,而且最早的时候,因为要集成或者解决问题,需要查看ansible源码,发现就是一坨。我好像不止一次跟别的同事说ansible是看过的最垃圾的开源代码。 最近又开始折腾了,虽然封装的接口还是不好用,但是看源码和修改给的example,最起码折腾起来轻松一点点了。源码也写的比之前好太多了。 playbook这玩意更坑,可能也是我写的不太多。

Continue

面试面到这个问题,以前只知道dba大概用的啥工具,从来没想自己搞过,现在面试要求有这方面技能,回答的不是太好,我只知道通过binlog可以支持异步同步,具体不知道怎么做。配置软件的事还要问,也是醉了。 先搞最简单的模式,mysql自带的replication,这个应该就是最普通读写分离的主从模式了,可以一写多读。流量不高还是可以的,然后需要加一下主备,我看之前一般是通过keepalived去做的,多主这种一般使用percona的工具去做的,支持强一致的模式,这些都没搞过。我看mysql文档,mysql支持innodb集群,支持多主,这个文档还没看,后面再研究。还提到一个NDB Cluster。 我的mysql是安装的8.0.26,看官网不但支持普通的replication模式,通过binlog日志和同步的位置来同步,还支持global transaction identifiers (GTIDs) 的模式,这个replication模式不需要binlog了,看名字是事务相关。相关的文档还没看,只是先走了一下普通的模式。 首先,需要设置实例的server_id,这个需要集群里唯一,可在/etc/my.cnf里面加一条 [mysqld] server-id=142 主从库都需要配置。 主库需要开启binlog,这个默认是开启的。从库视情况,如果需要作为别的从库的主库,也是必须要开启的。 从库需要配置一下relay-log,默认是按照主机名配置的,说是防止主机名变动,导致错误。 relay-log=/var/lib/mysql/re-relay-log relay-log-index=/var/lib/mysql/re-relay-log.i 创建用于同步的专属用户 mysql> CREATE USER 'repl'@'%.example.com' IDENTIFIED BY 'password'; mysql> GRANT REPLICATION SLAVE ON *.* TO 'repl'@'%.example.com'; 官网说,这个用户的密码是明文保存在从库中的,所以为了安全还是有必要创建一个的。 然后需要确定binlog同步的位置 先在主库加表的读锁,这样会阻塞写事务的提交。 mysql> FLUSH TABLES WITH READ LOCK; 新启动一个mysqlsession,执行SHOW MASTER STATUS,查看binary log的文件名和位置。文档说如果之前主库禁止了binlog,这个命令会返回空,在后边需要用到这俩值的时候,文件名为'',位置为4 释放锁的命令, UNLOCK TABLES; 最后一步是涉及在从库配置刚刚日志位置信息和主库信息。分两种情况,一种是新搭建的集群,另一种是主库本来有数据的情况。 我是刚搭建的环境,先用第一种。不同版本的mysql有两种方式,从8.0.23版本开始使用下面的语句 CHANGE REPLICATION SOURCE TO SOURCE_HOST='10.1.11.142', SOURCE_USER='repl', SOURCE_PASSWORD='123456', SOURCE_LOG_FILE='binlog.000001', SOURCE_LOG_POS=1012; 使用START REPLICA 启动同步 查看从库状态: show slave status\G Slave_IO_Running: Yes Slave_SQL_Running: Yes 这两个状态为yes基本就没啥问题了 第二种情况,需要手动先把已有的数据从主库同步到从库中,其他一致。官方推荐使用mysqldump,特别是使用innodb引擎的时候。这种模式需要保持表锁不释放,不能退出session。 mysqldump 添加--master-data参数会包含CHANGE REPLICATION SOURCE 语句。然后导入到从库中。文档说有mysql插件可以方便做到数据迁移和从库配置。 又大概看了一些replication实现的文档,主实例有一个dump线程, SHOW PROCESSLIST里为Binlog Dump。从库两个线程,一个线程接受主库的dump线程的数据,写到单独日志文件,上边状态的Slave_IO_running为这个线程状态。一个线程应用前一个线程的relay日志的线程。多从的情况,主库会为每个从库配置一个dump线程。 复制的数据格式,有三种模式,一种基于语句的( statement-based replication),这种的在特定语句引擎会造成数据不一致。默认是基于行数据的( row-based logging),这种好像是复制更改内容的。还有一种是混合模式,是前两种的结合。

Continue

本来以为很快安装完了,没想到安装过程中缺少不少文件,就决定再记录一下吧。 看系统软件库里版本太低,我就想直接源码编译安装。官网下载了2.4.3的版本。 编译命令:make -j $(nproc) TARGET=linux-glibc USE_OPENSSL=1 USE_LUA=1 USE_PCRE=1 USE_SYSTEMD=1,这个是开启所有模式的编译方式,可看INSTALL文件配置 需要安装gcc:yum install gcc.x86_64 需要pcre:yum install pcre-devel.x86_64 需要openssl: yum install openssl.x86_64 openssl-devel.x86_64 需要安装lua,需要5.3版本以上,我从lua官网下载了5.4.3版本,可以直接make后,指定lua目录。make -j $(nproc) TARGET=linux-glibc USE_OPENSSL=1 USE_LUA=1 USE_PCRE=1 USE_SYSTEMD=1 LUA_INC=/opt/source/lua-5.4.3/src/ LUA_LIB=/opt/source/lua-5.4.3/src/ 需要systemd-dev:yum install systemd-devel.x86_64 然后我现在记录才发现,就是参数指定的都需要额外安装的软件。 haproxy 配置文件 mkdir /etc/haproxy cp examples/option-http_proxy.cfg /etc/haproxy/haproxy.cfg 配置systemd cd admin/systemd/ make 会生成一个haproxy.service,我看就执行了替换bin目录 cp haproxy.service /usr/lib/systemd/system/ systemctl enable haproxy 直接start还是有问题,日志查看错误,需要改一下默认的配置文件和设置ulimit。 具体的详细配置还没看,只先瞟了一眼logging的配置。

Continue