ssh免密登陆

ssh免密登陆并不是什么复杂的事,但是配置了以后,会很方便。为了实现这个,在网上找了一些教程,也不知是服务器的默认配置的问题,还是什么原因,一直没有成功。

今天又试了下,在大语言模型智谱清言的帮助下,实现了免密登陆。记录一下。

客户端生成密钥

命令行中输入ssh-keygen -t rsa,然后一路回车,可以在当前用户的文件夹下的.ssh目录里生成两个文件,id_rsa.pub和 id_rsa。id_rsa.pub是公钥,可以给别人的,另一个是私钥,只能在自己电脑上的。

客户端复制公钥到服务端

如果是windows系统,这时就最好是用winscp一类的工具软件连接服务器,linux系统,可以用ssh-cp-id命令。

我是用的windows,下面说下怎么操作。

首先ssh登陆远程服务器,然后cd到当前用户下的.ssh目录里,ls查下有无authorized_keys这个文件,如果没有,使用touch authorized_keys创建这个文件。

然后,nano authorized_keys打开这个文件,也可以用vi。

第三步,用记事本打开客户端用户文件夹下.ssh目录中的id_rsa.pub文件。

第四步,复制id_rsa.pub中的全部内容。

第五步,到nano authorized_keys的编辑界面,右键,自动会把刚刚复制的内容粘贴到编辑界面中。

第六步,ctrl+o,再回车,保存文件。

第七步,ctrl+x,退出编辑。

修改服务端文件权限

服务器上~/.ssh/authorized_keys文件的权限是600,使用chmod 600 ~/.ssh/authorized_keys修改。

修改服务端ssh配置文件

这步可以在客户端的ssh界面操作。

配置文件通常是/etc/ssh/sshd_config,确保下面的配置是这样的。

1
2
3
RSAAuthentication yes
PubkeyAuthentication yes
AuthorizedKeysFile .ssh/authorized_keys

重启sshd,service sshd restart

非22端口的操作

对于22端口的,上面的操作基本就完成了,再用ssh连的时候,ssh user@ip,就可以登陆了,对于非22端口的,再记端口,麻烦,可以用config文件来搞定。

在客户端的.ssh目录下,新建一个config文件,不要后缀。

在里面写上下面这些行

1
2
3
4
5
Host ssh连接的名称
User 用户名
Port 端口号
HostName 服务端的域名或ip地址
IdentityFile id_rsa

大功告成。

编程基础-变量、地址与指针

地址

前面咱们说了,数据在存储过程中,为了方便,将存储介质分成了不同的区域和格子。为了方便的找到数据,又给每个存储的格子,也就是存储单元,分配了地址。但是这些地址是一长串数,不好记,怎么办?起个名字吧,这个名字,就是变量名。为什么叫变量名呢?因为这个地址里的数据,大多数时候,是可以修改的,也就是可以变化的,所以叫变量名。

变量

说是变量,其实有些数据在运行的时候是不变的,那些就叫常量,常量可以说是变量的一种特例吧。变量其实就是内存中数据的一个别名,方便是记忆和使用的。知道了这个名字,就知道这个数据在哪里(地址),也就能找到数据值了。注意,这里的数据不指定具体的类型。

变量类型

但是,就像数学中,有整数,小数,实数,复数等等类型一样,计算机中,数据也是有类型的。但是,前面不是说了么,计算机中数据存的时候只是0或1这样存的,怎么表示不同的类型呢?这其实中间要有一个翻译的过程。比如0b 0010,如果说它是整数类型,也就整型,那它就表示3,为什么是3呢?因为0010是二进制,转成十进制,就是3。那如果说它是字符型,它是什么字符呢?可以查下ascii码表,查表可知,它表示ETX这个特殊符号。

所以,变量类型存在的意义,就是把存储单元中存储的二进制数据转变成实际数据时用到的一个翻译选项,不同的变量类型,在翻译的时候要用不同的翻译方法。

指针

那指针,又是什么东西呢?指针,其实就是地址。它,可以是任意类型数据的地址。这就厉害了,任意类型的数据都有指针,所以,指针也有指针,或者说,地址也有地址,就好像你家有一个地址,但是这个地址在物业那里有一个通讯录,通讯录里有你家的地址,你家的地址在通讯录的某页某行处。你家,可以看成是一个存储单元,你家的地址是你家的指针,假设你叫张三,那“张三家”,就是你家的别名,也就是你家的变量名,你家地址在物业通讯录里的那条记录,就是你家地址的指针,也就是你家指针的指针。

理论上,指针可以有很多级,或是很多层,但实际应用中,别太复杂,不然就分不清了。

编程基础-二进制与存储单元

前言

这是本系列的第一篇,目标受众是0基础的,想学编程的人。

二进制

说起二进制,首先想到的是十进制。平时我们数数,就是用的十进制,为什么叫十进制呢?因为数的过程中,从0开始,每次+1,都会让数增大,但位数不变,都是1个数字,直到9+1=10,这时,1个数字不够用了,用了2个数字,这两个数字组合成一个新的数。这就叫进1。所谓的进1,也就是个数,准确的说,是位数,增加1个。十进制,就是逢十进一。个位进一位到十位,十位进一位到百位。

类比十进制,二进制,就是逢二进一,这时就不能叫个位,十位,百位了,叫第0位,第1位,第2位……。

第0位,逢二进一,那数的时候,0,表示0,1,表示1,10呢?表示的是2,11呢?表示的是3。但是我们也发现了,单独写10,看不出是十进制的十,还是二进制的10,为了区分,就需要用一个标识。计算机里用的是0b前缀表示二进制,而十进制,不用加前缀。

下面是二进制数对0-10的数据的表达。

二进制 十进制
0000 0
0001 1
0010 2
0011 3
0100 4
0101 5
0110 6
0111 7
1000 8
1001 9
1010 10

为什么用二进制

明明大家都是用的十进制,为什么要发明二进制呢?因为二进制方便计算机计算。为什么计算机方便用二进制计算呢?

二进制的基本数字,就是0,1,而十进制的基本数字是0-9,你能想到什么样的电路可以实现0-9的表达么?在电学里,电信号,一般就是电压、电流、电容、电感、电阻。要想找到不的数字的表达,这些表达就需要分成不同的等级,类似楼梯一样。如果是用电压来表示0-9的数字,按前面分析的,需要找到10个不同的等级来分别表示0-9,而二进制呢,只需要用2个不同的等级来表示0,1,很明显,二进制更简单一些。而十进制要复杂的多。所以,在电子计算机里,二进制得到了广泛的应用。

题外话:在以前,计算机也并不全是二进制的,苏联曾经开发出三进制的计算机,后面应用范围远不及二进制的,也就慢慢消失了。

其他进制

事实上,我们生活中也不只是有十进制,还有十二进制,就是时间,上午1点到12点,下午又是1点到12点。

在计算机领域中,除了二进制、十进制,还有十六进制、八进制。实际用的多的,就是二进制、十六进制和十进制。

数据的存储

可以存数据的东西,有光盘、磁带、硬盘等等,以上这些,存储的原理多少有些不同,但是本质是一样的。它们存的都是0或1,像光盘,是用激光在盘面上烧刻出不同长度的沟,短的是0,长的是1,磁带,是用强磁让磁带一段一段的磁化,留下不同长度的磁条,长的磁条是1,短的磁条是0。磁盘与磁带相似。

也就是说,他们都是存的0或1,用留下的记号的不同来标识。

扯个题外话。0或1这样的数据,本身是不连续的,因为在0和1之间还有无穷多个小数。这些不连续的数据,也被称为离散的数据,那计算机中有连续的数据么?很不幸,没有。计算机中不能直接处理和存储连续的数据。比如一段音乐,如果是用胶片存,胶片存的就是连续的,而CD盘,就不是连续的。那离散的为什么听不出来?同一段音乐,为什么又有胶片存的,又有CD存的,还有MP3文件存的?这些就涉及到了一些模数转换和数模转换了。简写为A/D转换(模数转换),D/A转换(数模转换)。

回到正题。从前面知道,数据计算机中存的是0,1这样的数。但是这些数要想好记,就需要给他们分个段,就像背电话号码,大家都用335或344的方式来分段记忆。同样,为了方便对二进制进行管理,在存储的时候,也对二进制进行了分段。

对于单一1个0或1,叫做一个bit,或比特,翻译过来,就是位。8个bit,就像前面写0-10那样,8个0/1组合,叫做一个字节,byte,为什么是8bit一个字节呢?因为最早计算机是美国搞的,他们把常用的字符编了一个表,用不同的数字表示不同的字符,刚好是127个,也就是7位,7这个数不利于分段,就搞了8位,4位一段。刚好8是2的3次方,8位最多可以表示2的8次方(255)个数。

数据在存储的时候,也是遵循这样的规律,最小的单位是1bit,但是这个单位太小了,就像分是中国货币的最小单位,但是现在很少有人直接说多少分,最少也是多少元。数据在存的时候也是,bit这个单位太小了。比bit大一级的,就是字节,byte,这个用的多一些。也是实际使用中,存储的最小单位。

计算机的数据存储,可以想像成一个大箱子,为了方便收纳,大箱子里又分了很多的区域,每个区域里又分了很多的格子。一个格子里只能存一个字节的数据,这一个字,就是最小的一个存储单元。在硬盘中,这个箱子,就对应着整块硬盘,不同的区域,就是不同的扇形区域,简称扇区,每个扇区下,又包括许多的字节。

数据索引

有过找东西经验的都会发现一个问题。东西是存起来了,但是想找的时候,如果没有提前记录存储位置,找起来就要一个格子一个格子的翻找,效率很低。怎么解决呢?一个很容易想到的方法是提前做一个记录,一条一条的记录着每个格子里存的是什么。这个记录表,不能离开这个箱子,他也要存在箱子里。当你有很多箱子的时候,为了方便找这个记录表,最好的方法是把这个表放在一个固定位置。硬盘里也是这样,在开始的位置,有一个文件记录表,记录表里记录着很个格子里都有什么内容。想要找某个东西的时候,先到这里找到记录表,再在记录表中找有没有想要找的东西。

这里忽略了一个问题,就是格子很多的时候,怎么区分不同的格子呢?聪明如你,给格子编上号就好了。按照一个固定的顺序,把每个格子都编上号码。这样,在找到要找的东西时,就知道了东西所在格子的编号。这像极了门牌号,所以,这个编号,又可以叫它 “地址”。当你开始在记录表中找要找的东西到你找到它的这段时间,在计算机里,叫 寻址

GNOME C规范

以下内容来自GNOME的开发文档,https://developer.gnome.org/documentation/guidelines/programming/coding-style.html

缩进

Linux 内核风格是一个tab缩进8个字符,GNU风格是一个tab 2个字符,这两种都可以,但要统一。

括号

if else,如果只有一条语句,可以不写大括号,如下:

1
2
3
4
5
/* valid */
if (condition)
single_statement ();
else
another_single_statement (arg1);

但也有例外。

第一种,if语句有大括号,else语句也要有大括号。

1
2
3
4
5
6
7
8
9
10
/* valid */
if (condition)
{
foo ();
bar ();
}
else
{
baz ();
}

第二种,单个语句写了多行,也要用大括号。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/* valid Linux kernel style */
if (condition) {
a_single_statement_with_many_arguments (some_lengthy_argument,
another_lengthy_argument,
and_another_one,
plus_one);
} else
another_single_statement (arg1, arg2);

/* valid GNU style */
if (condition)
{
a_single_statement_with_many_arguments (some_lengthy_argument,
another_lengthy_argument,
and_another_one,
plus_one);
}
else
{
another_single_statement (arg1, arg2);
}

第三种,如果if的条件有多行,也需要用大括号。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/* valid Linux kernel style */
if (condition1 ||
(condition2 && condition3) ||
condition4 ||
(condition5 && (condition6 || condition7))) {
a_single_statement ();
}

/* valid GNU style */
if (condition1 ||
(condition2 && condition3) ||
condition4 ||
(condition5 && (condition6 || condition7)))
{
a_single_statement ();
}

第四种情况,if嵌套,这时也需要用大括号。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/* valid Linux kernel style */
if (condition) {
if (another_condition)
single_statement ();
else
another_single_statement ();
}

/* valid GNU style */
if (condition)
{
if (another_condition)
single_statement ();
else
another_single_statement ();
}

函数

函数返回值类型独占一行

1
2
3
4
5
void
my_function (void)
{
// ...
}

函数参数一行一个,参数名称左对齐

1
2
3
4
5
6
7
8
void
my_function (some_type_t type,
another_type_t *a_pointer,
double_ptr_t **double_pointer,
final_type_t another_type)
{
// ...
}

空格

在括号前加空格,不要在括号后加空格

1
2
3
4
5
if (condition)
do_my_things ();

switch (condition) {
}

定义结构体时,使用空行,将不同类型的数据隔开

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
struct _GtkWrapBoxPrivate
{
GtkOrientation orientation;
GtkWrapAllocationMode mode;

GtkWrapBoxSpreading horizontal_spreading;
GtkWrapBoxSpreading vertical_spreading;

guint16 spacing[2];

guint16 minimum_line_children;
guint16 natural_line_children;

GList *children;
};

不要随便删除空行或空格,下面是错误的示范

1
2
/* invalid */
if (condition) foo (); else bar ();

switch

每个case的缩进级别应该相同,而且case的缩进应该与switch的大括号级别一致,一个case结束后,加一个空行,再开始下一个case。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
/* valid Linux kernel style */
switch (condition) {
case FOO:
do_foo ();
break;

case BAR:
do_bar ();
break;
}

/* valid GNU style */
switch (condition)
{
case FOO:
do_foo ();
break;

case BAR:
do_bar ();
break;

default:
do_default ();
}

头文件

头文件中函数定义要用三列。

1
2
3
return_type          function_name           (type   argument,
type argument,
type argument);

每列最大的宽度要以每列中最大的宽度为准。

1
2
3
4
void        gtk_type_set_property (GtkType     *type,
const char *value,
GError **error);
const char *gtk_type_get_property (GtkType *type);

如果要定义一个公共库,把小的头文件包括到单一的一个公共库头文件中,而不是在应用中导入多个小的头文件。比如,GTK库定义了一些头文件,但是能直接调用的,就是gtk.h,其他的库不能在应用中直接调用。

1
2
3
4
5
6
// The __GTK_H_INSIDE__ symbol is defined in the gtk.h header
// The GTK_COMPILATION symbol is defined only when compiling
// GTK itself
#if !defined (__GTK_H_INSIDE__) && !defined (GTK_COMPILATION)
#error "Only <gtk/gtk.h> can be included directly."
#endif

对于库,所有的头文件都要有inclusion guards。下面这串代码演示了如何使用#ifndef和#endif来避免头文件被重复引用。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#pragma once
//Time Class definition
//member functions are declared in time.cpp

//prevent multiple inclusions of header
#ifndef TIME_H
#define TIME_H

//time class definition
class time
{
public:
Time();//constructor
void setTime(int, int, int);//set hour, minute and second
void printUniversal() const;//print time in universal-time format
void printStandard() const;//print time in standard-time format

private:
unsigned int hour;//0-23
unsigned int minute;//0-59
unsigned int second;//0-59

};

#endif // !TIME_H

GObject 类

类型声明应该放在文件最开始的位置

1
2
typedef struct _GtkBoxedStruct       GtkBoxedStruct;
typedef struct _GtkMoreBoxedStruct GtkMoreBoxedStruct;

下面的没看懂什么意思……

内存申请

在堆栈中动态申请内存,用g_new(), 公共的结构类型要填充0,或是使用g_new0()来申请内存。

宏Macros

尽量避免用私有宏,返回的时候,记得#undef它们,最好是使用inline函数。公共宏除非是返回一个常值,否则不要使用。

gtk gdb调试时不显示界面的一种情况

问题环境:win10,ucrt64,gtk4

上午的时候在vscode下成功调试了gtk的程序,但是晚上就不行了,能进到gdb,但是不显示窗口,网上查也没查到原因。后面回想了下当前和早上时候的不同,好像就是打开了一个glade的界面,而glade打开的时候,会占用ucrt64的一个控制台。

有了猜想就验证,关闭glade,再调试,一小会,界面就出来了。看来还真的是这个原因。后面又打开glade,再调试,还是不行,调试运行时,关闭glade,一小会儿,窗口就显示出来了。

gtk使用ui文件定义界面运行报错

今天在照着gtk的官方教程做示例的时候,遇到一个问题,就是下面的链接,https://docs.gtk.org/gtk4/getting_started.html

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
#include <gtk/gtk.h>
#include <glib/gstdio.h>

static void
print_hello (GtkWidget *widget,
gpointer data)
{
g_print ("Hello World\n");
}

static void
quit_cb (GtkWindow *window)
{
gtk_window_close (window);
}

static void
activate (GtkApplication *app,
gpointer user_data)
{
/* Construct a GtkBuilder instance and load our UI description */
GtkBuilder *builder = gtk_builder_new ();
gtk_builder_add_from_file (builder, "builder.ui", NULL);

/* Connect signal handlers to the constructed widgets. */
GObject *window = gtk_builder_get_object (builder, "window");
gtk_window_set_application (GTK_WINDOW (window), app);

GObject *button = gtk_builder_get_object (builder, "button1");
g_signal_connect (button, "clicked", G_CALLBACK (print_hello), NULL);

button = gtk_builder_get_object (builder, "button2");
g_signal_connect (button, "clicked", G_CALLBACK (print_hello), NULL);

button = gtk_builder_get_object (builder, "quit");
g_signal_connect_swapped (button, "clicked", G_CALLBACK (quit_cb), window);

gtk_widget_set_visible (GTK_WIDGET (window), TRUE);

/* We do not need the builder any more */
g_object_unref (builder);
}

int
main (int argc,
char *argv[])
{
#ifdef GTK_SRCDIR
g_chdir (GTK_SRCDIR);
#endif

GtkApplication *app = gtk_application_new ("org.gtk.example", G_APPLICATION_DEFAULT_FLAGS);
g_signal_connect (app, "activate", G_CALLBACK (activate), NULL);

int status = g_application_run (G_APPLICATION (app), argc, argv);
g_object_unref (app);

return status;
}

官方给的代码,没有说builder.ui这个文件放在哪里,我就放到了和main.c同级的子目录下,结果编译能通过,但是运行时报错。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
(main.exe:53272): Gtk-CRITICAL **: 23:14:02.343: gtk_window_set_application: assertion 'GTK_IS_WINDOW (window)' failed

(main.exe:53272): GLib-GObject-CRITICAL **: 23:14:02.348: invalid (NULL) pointer instance

(main.exe:53272): GLib-GObject-CRITICAL **: 23:14:02.351: g_signal_connect_data: assertion 'G_TYPE_CHECK_INSTANCE (instance)' failed

(main.exe:53272): GLib-GObject-CRITICAL **: 23:14:02.356: invalid (NULL) pointer instance

(main.exe:53272): GLib-GObject-CRITICAL **: 23:14:02.360: g_signal_connect_data: assertion 'G_TYPE_CHECK_INSTANCE (instance)' failed

(main.exe:53272): GLib-GObject-CRITICAL **: 23:14:02.364: invalid (NULL) pointer instance

(main.exe:53272): GLib-GObject-CRITICAL **: 23:14:02.367: g_signal_connect_data: assertion 'G_TYPE_CHECK_INSTANCE (instance)' failed

(main.exe:53272): Gtk-CRITICAL **: 23:14:02.372: gtk_widget_set_visible: assertion 'GTK_IS_WIDGET (widget)' failed

由于刚开始学,也不太会调试,完全没有头绪。但是编译能通过,觉得代码应该是没问题的。就猜,可能是ui文件路径不对。就试着改了两下,最后试出来了,gtk_builder_add_from_file (builder, "builder.ui", NULL); 这句中的builder.ui应该写这个项目中的相对路径,或是绝对路径。我放到了项目目录的src文件夹下,用相对路径写法,应该写成gtk_builder_add_from_file (builder, "src/builder.ui", NULL);,再次make run,就不再报错了。

如果这个以后想换个位置也能运行,这个ui文件应该放到另外的一个目录下,到时再研究怎么发布exe吧。

windows安装gtk4并配置VSCode进行编程

下载MSYS2

gtk的网站上是这样写的

There are various methods to install GTK on Windows development machines.

MSYS2

This method is based on the packages provided by MSYS2, which provides a UNIX-like environment for Windows. Both of these repositories also provide packages for a large number of other useful open source libraries.

gvsbuild

This method provides scripts to build the GTK stack from source and outputs libraries and tools that can be consumed by Visual Studio or Meson based projects.

意思是有两种方法在windows平台上安装gtk,一种是用MSYS2,一种是用gvsbuild。我选的是MSYS2这个路径。

https://www.msys2.org/ 从这个网址下载,一打开就可以看到下载链接,很显眼。跟着指导步骤一步一步做。
msys2下载

需要注意的是,按照这个网站上的安装方法,会安上 UCRT64 环境,这个环境是基于MinGW64的,很多教程里边,环境变量,include路径基本都是用的MinGW的路径。

安装GTK4和依赖

在第一步完成时,就打开了一个命令行窗口,如果不小心关了,可以从开始菜单找到MSYS2 UCRT64,点它,启动。运行pacman -S mingw-w64-ucrt-x86_64-gtk4,如果想安装gtk3,则运行pacman -S mingw-w64-ucrt-x86_64-gtk3

安装工具链(可选)

如果要在C、C++等语言下使用GTK,需要安装编译器,比如GCC和它的工具链。pacman -S mingw-w64-ucrt-x86_64-toolchain base-devel,如果是使用Python,需要安装Python包,pacman -S mingw-w64-ucrt-x86_64-python-gobject

配置VSCode

由于VSCode免费,支持多种语言,所以计算机上安了VSCode,不想再安其他的IDE,就配一下VSCode吧。结果遇到了很多坑。

设置环境变量

在系统环境变量的PATH中,填加MSYS2中的msys64\ucrt64\bin,当然,主要还是看哪个目录的bin文件夹下有内容。

设置完环境变量,打开cmd,输入gcc --version,可以看到回显数据。

安装VSCode插件

一个项目管理的Easy C++ project,一个是C/C++代码提示的Microsoft C/C++ 扩展

创建C++项目

vscode打开新建的文件夹,按下键盘F1输入easy cpp,选择Create new C++ proejct,然后选择[G++/GDB] Linux,Windows系统也是选这个,因为只有这个才是用mingw的。

获取include path

打开MSYS2 UCRT64 在命令窗口输入pkg-config --cflags gtk4 | sed 's/ /\n/g' | sed '1,3d;s/-I\(.*\)/\1/g' | sort | uniq,将输出的结果复制。注意,复制的时候,有几项是短横线-打头的,不是文件路径的项,不要复制这些。

设置include path

在vscode按下F1,选择C/C++:编辑配置(UI),这将自动生成c_cpp_properties.json文件并且进入图形界面进行修改。将前面复制的路径,贴到包含路径处。注意,图片只是示例,不是真实值。这里的路径,不太全,需要手动再填加两个,一个是include/gtk-4.0,一个是include/pango-1.0。如果不加这两个,VSCode的代码检查总是会提示有文件找不到,其实没啥事。

设置includePath

修改Makefile

下面是我用的Makefile

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
CXX		  := g++
CXX_FLAGS := `pkg-config --cflags gtk4`

BIN := bin
SRC := src
INCLUDE := include
LIB := lib

LIBRARIES := `pkg-config --libs gtk4`
EXECUTABLE := main


all: $(BIN)/$(EXECUTABLE)

run: clean all
clear
./$(BIN)/$(EXECUTABLE)

$(BIN)/$(EXECUTABLE): $(SRC)/*.cpp
$(CXX) $(CXX_FLAGS) -I$(INCLUDE) -L$(LIB) $^ -o $@ $(LIBRARIES)

clean:
-rm $(BIN)/*

launch.json和task.json

做出上面的修改后,编译是可以了,但是要手动打命令,如果要点下面的build & run,则需要修改task.json,第一次运行时,会在右下角提示生成task.json。我改成下面这样了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
{
"version": "2.0.0",
"tasks": [
{
"label": "Build C++ project",
"type": "shell",
"group": "build",
"command": "make"
},
{
"label": "Build & run C++ project",
"type": "shell",
"group": {
"kind": "test",
"isDefault": true
},
"command": "make",
"args": [
"run"
]
},
{
"type": "cppbuild",
"label": "C/C++: g++.exe 生成活动文件",
"command": "C:/msys64/ucrt64/bin/g++.exe",
"args": [
"-fdiagnostics-color=always",
"-g",
"${file}",
"-o",
"${fileDirname}\\${fileBasenameNoExtension}.exe"
],
"options": {
"cwd": "C:/msys64/ucrt64/bin"
},
"problemMatcher": [
"$gcc"
],
"group": {
"kind": "build",
"isDefault": true
},
"detail": "调试器生成的任务。"
}
]
}

调试的话,需要配置launch.json。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
{
"version": "0.2.0",
"configurations": [
{
"name": "C++ Debug (gdb)",
"type": "cppdbg",
"request": "launch",
"program": "${workspaceFolder}/bin/main",
"preLaunchTask": "Build C++ project",
"args": [],
"stopAtEntry": false,
"cwd": "${workspaceFolder}",
"environment": [],
"externalConsole": true,
"MIMode": "gdb",
"miDebuggerPath": "gdb.exe",
"setupCommands": [
{
"description": "Enable pretty-printing for gdb",
"text": "-enable-pretty-printing",
"ignoreFailures": true
}
]
}
]
}

线规格,端子规格,压线钳规格

线规格

线规格现在主要说美标的,以AWG标识,数字越大,线越细。

线规格.png

图上展示了不同规格的线的直径、截面积、导流能力。

端子规格

端子形式有很多,但与线相连接的部分就三种形式。

柱状端子

把线穿进圆柱里,把圆柱夹线,把线固定,这种一般线不是很粗,线套上这个端子后,可以很方便的接到种子端子排上。

柱状端子

类似杜邦头端子

压线时两片压线芯,两片压线皮,需要用专用钳子压端子。

类杜邦头端子

大圆柱鼻状端子

有较大的线鼻,一般是U形口,或是扁口的端子上用,压的时候与第二种类似,但是一般是压中间一处,而不是两处。

大线鼻

压线钳规格

不论是何种端子,都有适应的线径,不是一个型号的端子可以压任意规格的线。而不同形式压接方式,可以选不同形式的钳子,但是钳子的规格,一般是以线径来说的。比如一个端子用的16AWG的线,那钳子应要用适配16AWG的钳子。由于线规格很多,所以钳子一般一个头上有多个槽位,可以压不同的线径,线径跨度再大点,还要换其它的钳子。大钳子压小线,压不紧,小钳子压大线,容易变形,甚至断线。

win10安装solidworks2016

win10离线安装SolidWorks2016的问题

安装过程很顺利,但是激活的时候,SSQ的激活程序一直运行,不提示“All done”的信息。上网检索了一圈,发现了问题的源头。

  1. 防火墙
  2. dotnet3.5

防火墙好办,dotnet3.5若是在线,很好安,但是离线安装不太方便。通过检索,找到了一个不错的解决方法。

解决方法

这个网址 找到对应的win10的版本,下载相应的dotnet3.5的包,然后照着命令执行就可以了。

测试验证

当dism显示dotnet3.5安装成功后,再执行SSQ的激活程序,很快就激活成功了。

jupyter notebook切换环境

在虚拟环境中安ipykernel

为了能被jupyter notebook识别,先要在虚拟环境中安装ipykernel,先进入虚拟环境,conda activate env_name, 再运行命令conda install ipykernel

在base环境里安装nb_conda_kernels

原理的详细用法可以看github上的说明https://github.com/anaconda/nb_conda_kernels 。操作方法,先回到base环境,conda activate,再运行conda install nb_conda_kernels。这个安装时会卡在solving environment那里几分钟。

另外看到有文章说,3.6版的python,需要安装的是conda install nb_conda,没有测试过。如果一直失败,不防试一试。

测试

安装完成后,从所有程序那里,打开jupyter notebook,新建一个notebook,然后选择kernel,这时如果可以看到多个不同的源,表示,安装好了。