本文是“攻玉计划”的一部分,翻译自 https://stackoverflow.com/questions/1041866/what-is-the-effect-of-extern-c-in-c 中 Ciro Santilli 的回答
main.cpp
1 | void f() {} |
将上述代码编译为 ELF 格式的二进制,然后反汇编:
1 | g++ -c -std=c++11 -Wall -Wextra -pedantic -o main.o main.cpp |
摘取一部分输出:
1 | 8: 0000000000000000 7 FUNC GLOBAL DEFAULT 1 _Z1fv |
可见:
ef
和 eg
在符号表中的名称与其在原先代码中的名称一致c++filt
工具还原其本来的样子:1 | $ c++filt _Z1fv |
所以,在以下两种情况下,我们需要使用 extern "C"
:
g++
可能会遇到由 gcc
生成的未修饰过的符号名g++
生成未修饰的符号名,以供 gcc
调用显然,任何需要使用 C++ 名称修饰的语言特性,都不能写在 extern "C"
中:
1 | extern "C" { |
在 C++ 中调用 C 代码很简单:每个 C 函数都只有一个未修饰的符号名,所以不需要额外的操作。
main.cpp
1 |
|
c.h
1 |
|
c.c
1 |
|
运行:
1 | g++ -c -o main.o -std=c++98 main.cpp |
如果没有 extern "C"
的话,链接器会报错:
1 | main.cpp:6: undefined reference to `f()' |
因为 g++
会寻找一个修饰过的 f
,但是 gcc
并不会编译出修饰过的符号名。
在 C 中调用 C++ 代码稍微困难一点:我们需要手动管理所有暴露给 C 的函数接口,并且使它们在编译时不被修饰。
代码如下:
main.c
1 |
|
cpp.h
1 |
|
cpp.cpp
1 |
|
运行:
1 | gcc -c -o main.o -std=c89 -Wextra main.c |
如果不加 extern "C"
的话,会报错:
1 | main.c:6: undefined reference to `f_int' |
因为 g++
会生成修饰后的符号名,但 gcc
无法理解。
cstdio
可能靠 #pragma GCC system_header
这个编译宏实现的,根据 https://gcc.gnu.org/onlinedocs/cpp/System-Headers.html :在某些平台,例如 RS/6000 AIX 上编译 C++ 代码时,GCC 会隐式地将所有系统头文件用 extern “C” 包含起来。但我并不完全确定。/usr/include/unistd.h
会使用 __BEGIN_DECLS
宏,而 __BEGIN_DECLS
会定义为 extern "C" {
。详见 https://stackoverflow.com/questions/8087438/do-i-need-an-extern-c-block-to-include-standard-posix-c-headers/8087539#8087539。航模的话,虽说十年前我就开始接触了,但一直都是浮于表面的玩,能动就行。玩航模必须要有遥控器和接收机,接收机也是输出 PWM 信号的,连接舵机就能控制其在指定角度范围内运动,连接电调就能控制电机转速。
于是,我想当然的,航模接收机 应该也是输出 0-100% 占空比的 PWM 信号,0 就是舵机一个极限角度,50% 就是中位,100% 就是另一个极限角度。
然而事实并不是,我把履带车的驱动板接上航模的接收机,不管我怎么推拉摇杆,履带车始终以一个非常低的速度运动。
这就引起了我的好奇。
手头没有示波器,就拿一个简单的逻辑分析仪应付一下:
我只测量 1 通道数据(通常是副翼/横滚通道)。
这是摇杆在中点:
摇杆在最左侧:
摇杆在最右侧:
真有趣,占空比始终在 5%~10% 左右。说明航模遥控器的 PWM 信号肯定不是简单靠占空比来控制舵机的。不然放着 10%-100% 这么大的空间不用,有点暴殄天物。
我查了很多论坛,一开始感觉很奇怪,他们(比如 这个 )基本上只谈 PWM 的脉冲时间长度为 1-2ms,以及频率“一般”为 50Hz,却几乎不谈占空比。
我看了一会突然醒悟了,因为 PWM 不是本来就叫“脉冲宽度调制”吗?只不过以前我都用它来调光、控制电机,所以才关注占空比,但 PWM 本身应该去关注“宽度”啊。
所以,就像 这里 回答的一样,航模舵机本身并不关注占空比是多少,只关注每个周期内,高电平的时间是多长。1ms 就代表最小角度,2ms 就是最大角度,1.5ms 就是中位。
因为一般频率是 50Hz,也就是周期为 20ms,所以占空比看起来才是 5%-10%。
至于为什么选择 50Hz,解释是:这个频率是舵机的工作频率而已,舵机要按照这个周期动作。太快舵机会吃不消,太慢的话,响应就慢了。
也有 200Hz 的舵机,但脉冲宽度也是 1-2ms,于是占空比就变成了 20%-40%。
当然也有部分舵机会用 0.5-1ms 以及 2-2.5ms 这个区间的脉冲宽度,以达到更大的舵量。
而对于电调而言,信号也是一样的,沿用舵机的信号就很方便。
另外为什么选择 1-2ms?因为很久以前的遥控器就这么规定了,不多说。
]]>在本站之前一篇文章 如何成为 CA,并签发自己的证书 中,我们介绍了如何做一个“正规”的自签名证书。
但是,这个方法对于现代的浏览器不太管用了,因为 Chrome、Firefox 等浏览器已经不再判定证书的 CN (Common Name) 字段与域名是否一致了,而是改用判定 SAN (Subject Alternative Name) 字段。具体为什么这么做以及 SAN 的含义,网上有很多解释,很重要但是这里不谈,只谈如何在自签名证书中正确配置 SAN 字段。
网上的教程有很多,但很多没有说清楚,或者缺少一些关键步骤和参数,导致实际情况下出各种问题,这里我尽量整理了一个完善的版本。
首先,CA 的证书与文首提到的文章一致,如果之前配置过,那就不需要再生成了。
然后,生成待签发证书的私钥,这一步也与上述文章相同:
1 | openssl genrsa -out example.key 4096 |
之前创建 CSR 的时候会手动输各个字段,但其中不包含 SAN 字段,所以我们需要一个配置文件来配置 SAN 字段(当然直接包含在命令行里面也行,但很麻烦)。
建议新建一个目录叫 certreq
,然后在里面新建一个文件叫 req.conf
,内容如下:
1 | [req] |
然后生成 CSR 文件:
1 | openssl req -new -key example.key -out example.csr -config req.conf |
1 | openssl req -noout -text -in example.csr | grep -A 1 "Subject Alternative Name" |
如果打印出了你的配置,则代表创建成功。如果没有输出,请检查有没有操作错误。
1 | openssl x509 -req -days 365 -in example.csr -CA /path/to/CAPrivate.pem -CAkey /path/to/CAPrivate.key -CAcreateserial -out example.crt -extensions req_ext -extfile req.conf |
注意其中的 -extensions req_ext -extfile req.conf
是关键,很多教程没有加这个参数,导致生成的证书丢了 SAN 字段。
1 | openssl x509 -text -noout -in example.crt | grep -A 1 "Subject Alternative Name" |
同上,需要打印出正确的 SAN 配置,才算成功。
]]>译者按:大部分人都知道,百兆以太网只用了 RJ45 端口中的 2 对 4 根线,分别为 TX、RX 的差分信号。
千兆以太网用了 RJ45 端口中的全部 4 对 8 根线,但是这 4 对 8 根线是怎么定义的?哪些属于 TX,哪些属于 RX?
我也不知道,而且以前居然没有认真去了解过,所以我决定找一篇与此相关的文章翻译一下,分享给大家。
本文是“攻玉计划”的一部分,翻译自 https://www.practicalnetworking.net/stand-alone/ethernet-wiring/
当我们谈到“以太网”的时候,我们可能会讨论各种概念,包括所有线缆规格(10BASE-T, 100BASE-TX, 1000BASE-T 等等)。这些协议规定了导线上的电平(即 0/1 信号)是如何传递的,也规定了如何将电平信号解析为数据帧。
本来,此文只想简单介绍一下交叉线和直通线之间的基本区别,但基于我们的 原则,我们觉得应该更深入一些。
首先,我们会先介绍一些术语,并消除一些歧义,然后回答一些基本的问题:我们为什么要用交叉线或者直通线?到底什么是双绞线?一个个比特位是如何在线上传播的?最后,我们会综合这些概念,并探讨一下千兆以太网的相关标准。
即使你刚接触网络通信不久,也应该听说了很多网线相关的概念,例如“以太网”“双绞线”“RJ45”“屏蔽线”“非屏蔽线”等。
但这些概念代表了什么含义?互相之间又有什么异同?有没有什么概念被误用了?坦白而言,这些概念经常被误用,不妨看看:
这是网线两端接口的物理标准,表示它有 8 个卡口位(Position)和 8 个触点(Contacts)。这也定义了此塑料透明接口的外形设计和尺寸。
标准插座接口(Registered Jack)第 45 号标准定义了线缆中导线的个数以及线序,并规定使用 8P8C 的物理接口。
特别地,RJ45 定义了两种线序标准:T568a 和 T568b:
请注意,两个标准唯一的实际区别是第 2 对线和第 3 对线的颜色不同。
很多人经常用 RJ45 来指代 8P8C 插口,但这是不对的。还有另一种叫 RJ61 的类似标准,也使用了 8P8C 的插口,但其内部的线序不一样。标准插座接口定义家族中还有很多其他 RJxx 的接口,但接线定义和物理尺寸都不一样。
双绞线是一种组合线缆,包含了 8 根独立的导线,其中每两根作为一对,每对的两根线互相绞绕在一起。由此得到 4 对导线,每对导线作为一个数据传输通道。
导线成对出现这一概念很重要,我们在后文中会讲到,简而言之,这有助于减少电磁干扰(EMI)。
通常,双绞线有两种规格:屏蔽线及非屏蔽线。
注意,不管哪种规格,网线中都有 4 对导线,也就是 4 个独立的数据通道。
非屏蔽线(Unshielded Twisted Pair)(UTP)在实际工程部署中更为常见。它对外部的电磁噪声没有额外的防护,但得益于双绞线的固有特性,其数据传输也非常可靠。我们将在后文详细阐述。
非屏蔽线更便宜,物理韧性更好,也更软。这些优点使得非屏蔽线在大多数场合更受欢迎。
屏蔽线(Shielded Twisted Pair)(STP)在每对双绞线、以及全部 4 对导线最外侧都包有额外的金属屏蔽壳,这有助于隔离信号传输时的电磁噪声。
但同时,如果屏蔽壳的某个地方出现了破损,或者屏蔽壳在网线两端没有都良好接地,它自身可能会成为一个天线,并且会因为空间中随处可见的无线电波(比如 Wi-Fi 信号)而给信号传输带来额外的电磁噪声。
更为甚者,屏蔽线必须与带屏蔽的 8P8C 插头一起使用,才能实现全链路端到端的屏蔽功能。
显然,屏蔽线肯定更贵,也比非屏蔽线更脆弱,因为如果屏蔽线被过度弯曲的话,其屏蔽壳很容易破损。因此,屏蔽线的使用场合比非屏蔽线少得多。
屏蔽线通常只会用在对电磁屏蔽高度敏感的场合,例如,网线紧挨着发电机或者重型机械的输电线等。
就像我们之前说的,以太网(Ethernet)是一系列标准的合集,其中之一就是不同的接线规格:10BASE-T,100BASE-TX,1000BASE-T 等等。
以太网协议也定义了每个比特(1 和 0)如何在线缆上传输,以及如何将这些比特流组合为有意义的数据帧。例如,以太网规定每帧数据的前 56 个比特必须是交替出现的 1 和 0(即“前导码”),接下来 8 个比特必须是 10101011(即帧起始标志),再接下来 48 个比特是目标 MAC 地址,然后是 48 个比特的源 MAC 地址……直到整个数据帧被全部传输完毕。
接下来,我们将讨论以太网标准中不同规格的接线规格。
本节讲述的概念都与网线内部的导线如何使用相关。例如,哪些用来发送数据,哪些用来接收数据,如何发送信号,以及电压等级。
BASE T* 这一概念有三个组成部分,所以在我们讲述特定的标准之前,先来单独了解一下它们,以 100 BASE-T 为例:
开头的数字表示网线每秒可以传输多少“兆(百万)”比特,即 Mbps。100Mbps 的网线理论上每秒可传输 100,000,000 个比特,大概每秒 12.5 兆字节(MBps),注意大写的 B 和小写的 b 分别代表字节和比特。
这一速率的网线有时被称为“快速以太网”,这是相较于 10Mbps 的“普通以太网”以及 1000Mbps 的“吉比特以太网”而言的。
base 这个概念是“基带”(baseband)信号的缩写,对应的概念是“宽带”(broadband)信号。这些概念刚出现的时候,其区别是:基带在介质中传输数字信号,宽带在介质中传输模拟信号。
数字信号和模拟信号的区别在于其可被解析的值个数。
模拟信号可以表示无数种不同的值,例如,我们可以用一根线上某个特定的电压值来表示一个绿色的像素点,而另一个电压值来表示红色的像素点,以此类推,这样,这根线就能传输一张图片上的每一个像素点。
数字信号可以表示有限个不同的值,通常就两个:1 和 0。如果上述的图片用一根数字信号线来传输的话,我们会传输一系列 1 和 0 的信号流。接收端可以解析这些二进制数据为一系列数字,例如基于 RGB 颜色编码,就能构造出每一个像素点。
也就是说,数字信号和模拟信号的主要区别就是,模拟信号线上可获得无穷多中不同的值,而数字信号线上,要么是 0,要么是 1,不可能出现第三种情况。
如此一来,数字信号传输具有更高的容错率,因为导线上的电压范围只被分为了两种情况(1 或者 0)。
译者按:原文在此处举了更多的例子来详细阐述“模拟信号”和“数字信号”的区别,但译者认为过于冗余,故略去这部分篇幅。
“-T”表示其为双绞线(Twisted Pair)。相似的标准还有“-2”及“-5”,表示其是最大长度为 200 和 500 米的同轴电缆,以及“-SR”和“-LR”,表示其为短距离(Short Range)和长距离(Long Range)光纤。
以上解释了 BASE T* 相关术语的三个独立部分,我们现在可以探讨下快速以太网的两个重要规范(对于吉比特以太网的相关规范,我们会在后文继续探讨):
100BASE-T4 使用了网线中全部 4 对 8 根线。其中一对仅仅用于发送信号(TX),一对仅仅用于接收信号(RX)。剩下两对既可以用于 RX 也可以用于 TX,这通过网线两端设备的协商来决定具体用途。
T4 是双绞线早期的标准之一,但由于其过于复杂且必要性不强,如今已很少使用。
100BASE-TX 只使用了网线中的 2 对 4 根线,其中一对用于 TX,另一对用于 RX,剩下两根线没有使用。你完全可以做一根只有 4 根线的网线以实现 100BASE-TX 的所有功能,只要插口触点位置正确即可(位号1,2,3,6),但通常网线铺设过程中,另外 4 根线也保留了下来,用于占位,并适配未来可能的场景升级。
100BASE-TX (包括全部 8 根线)是如今最常用的快速以太网标准。但是,它通常被简写成了 100BASE-T。再强调一下,T 只表示其为双绞线,而 TX 才表示其使用了 1&2 及 3&6 两对线。
以上介绍可从实用性和技术性的角度帮读者理解相关概念。而在实际情况中,即使你不理解原理,直接使用这些产品也非常简单,就算犯一些小错误,也是允许的。
网上能找到很多“交叉线”及“直通线”应用场景的相关教程,但他们一般很少解释其原理。本节我们会深入探讨一下相关概念。
100BASE-TX 及 10BASE-T 标准中定义的网线,都包含 8 根导线,两两以双绞线的形式结合为 4 对。
在这四对线中,实际只用到两对:第 2、3 对。每根线都是单工的介质,也就是说,信号只能按照指定的单方向传输。
为了实现全双工通讯,某对线将始终沿某个方向传输数据,而另一对线将始终沿相反的方向传输数据。
网络接口卡(Network Interface Card)(NIC)的配置会决定哪对线用于发送数据,哪对线用于接收数据。
使用第 2 对线(1 号和 2 号引脚)发送数据(TX)、且使用第 3 对线(3 号和 6 号引脚)接收(RX)数据的的 NIC 被称作介质相关接口(Media Dependent Interface)(MDI),与之相反,使用第 3 对线作为 RX、第 2 对线作为 TX 的 NIC 被称为交叉模式介质相关接口(Media Dependent Interface Crossover)(MDI-X)。
假设一台电脑使用 MDI 模式的 NIC ,那么它就总是用第 2 对线发送数据,用第 3 对线接收数据。但如果两台用网线连接在一起的电脑都用第 2 对线发送数据,那么就会产生冲突。与此同时,两台电脑也都无法从第 3 对线上接收到数据。
因此,网线对需要交叉一下,以便从一台电脑的第 2 对线发送的数据,会被另一台电脑的第 3 对线接收到,反之亦然。
下图是一个简单的示意(无需在意示意图中线的颜色,这只是为了区分两个不通的路径而已):
注意,两台电脑都在独立的通道上发送数据,并且依靠交叉线机制(如图所示中间的 X),两台电脑都能接收到对方发送的数据。
因此,两台电脑直连后,必须使用交叉线才能通讯。
交换机使得同一网络下两台电脑的通讯变得更简单。交换机的 NIC 都采用 MDI-X 标准,也就是说,交换机总是在第 3 对线上发送数据,在第 2 对线上接收数据(与电脑的 NIC 相反)。
也就是说,交换机内部有一个交叉的机制,网线本身也就不需要交叉了:
可见,连接在交换机上的电脑可以直接使用直通线,让交换机处理线序交叉即可。端到端的通讯路径也是一样的:每个设备都在自己的 TX 线上发送数据,在 RX 线上接收数据。
我们刚刚讨论了,两台电脑直连,需要使用交叉线;类似的,两台交换机之间也需要交叉线:
在这种情况下,端到端的通讯路径也与上述方式无异。
那么,路由器和集线器呢?他们用了怎样的 NIC ?
实际情况是,路由器与电脑类似,使用了 MDI 标准(第 2 对线是 TX,第 3 对线是 RX),因此,你可以将上述图片中的任意电脑换成路由器,通讯路径分析也是一样的。
而集线器与交换机类似,使用 MDI-X 标准。
译者按:此处的“路由器”是狭义上仅具有“路由”功能的设备,不等于常见的家用无线路由器
前文讲到,RJ45 的导线颜色有两种标准:T568a 和 T568b。双绞线两侧所使用的标准决定了其是交叉线还是直通线。
要想做一根直通线,只要保证线两端的标准一致就行了,都是 T568a 或者都是 T568b:
要想做一根交叉线,只需其中一端为 T568a,另一端为 T568b 即可。
注意,第 1 对线和第 4 对线没有使用(蓝色对和棕色对)。理论上你的网线中可以去掉这几根线,但是去掉之后剩下的线排列起来有些困难。
另外,这两对线因为用不到,所以无需交叉。但是,吉比特以太网标准需要用到全部 8 根线,所以为了一致性,通常所有网线对都被交叉。我们会在后文讨论吉比特以太网。
最后需要注意的是,数据信号本身并不在乎导线的颜色,只要它们连在了正确的接口上就能通讯。但能用不代表就是一个好主意,颜色乱接的话,后续维护起来就是噩梦。
综上所述,我们可以把交叉线和直通线的用法画作一张图:
之所以这么摆放,是因为这样画起来更方便。我们把 L1、L2 层的设备画在左右两侧,L3 层设备画在上下两边,然后两两连接。关于网络协议分层请参见 OSI 模型。
小结一下:
或者更简单:
即使知道了什么时候该用直通线,什么时候该用交叉线,对于网络工程师来说,布线也常常是个头疼的事情。
于是,出现了一个新技术,可以自动分析两台设备的接口模式,并决定是否要交叉 TX/RX。这个技术叫做“自动 MDI-X”。
使用自动 MDI-X 技术,任意两台设备之间都可以通过直通线连接,并让两端动态确定是否需要交叉 TX 和 RX。
自动 MDI-X 是 100BASE-T 实现中的一个可选功能,而在所有吉比特以太网设备中是必须的。
那么,自动 MDI-X 是如何实现的?两端的设备如何确定哪对线是 TX 或 RX?如果有必要的话,哪一边的设备会交换 TX 和 RX?本节会介绍其内部工作原理。
记住,交叉线的目的是让一方的 TX 连接到另一方的 RX。也就是说,一方的 NIC 必须用 MDI 标准,另一方必须是 MDI-X 标准。自动 MDI-X 是这样实现这一功能的:
双方都先生成 1-2047 中的一个随机数,如果随机数是奇数,那么这一方会将自己的 NIC 配置为 MDI-X 模式;如果是偶数,则配置为 MDI 模式。而后双方就开始在其所选择的 TX 线上发送连接脉冲信号。
如果双方都能在自己的 RX 线上收到对方的连接脉冲,那么就代表协商完成,因为双方都能在 TX 线上发,在 RX 线上收。
如果双方都不能收到对方的连接脉冲,那么它们肯定都随机到了奇数或都随机到了偶数。因此,它们中的某一方必须将自身的 TX 和 RX 交换。
但是双方不能同时交换 TX 和 RX,因为这样一来依然是冲突的。因此,我们设计了一个系统,以随机的时间间隔切换 TX/RX 对,直到双方成功协商。
前文提到随机生成的数字(1-2047)会循环变化,以便双方能选择一个新的标准(MDI 或者 MDI-X)。但是这个数字不能每次加 1,因为这样的话,双方都会从奇数变为偶数,或者偶数变为奇数。换句话说,如果双方一开始都选择了 MDI 模式,如果同时加 1,它们都会切换为 MDI-X 模式,依然无法协商。
所以,这个随机数使用了叫“线性反馈移位寄存器”的设备以实现循环变化。
线性反馈移位寄存器(Linear-Feedback Shift Register)(LFSR)是一种算法,它会循环遍历某个范围内的所有数字,而且在每一个循环内不会重复。这些数字以一种可预测的、但随机的顺序循环出现(也就是说,它们不按照大小顺序依次出现,但出现的位置是确定的)。
举个例子,如果双方随机的初始值分别为 1000 和 2000,那么它们在 LFSR 序列中下一个数字的奇偶性是完全随机的。但如果双方随机到了同一个初始值,那么它们之后随机出来的数字依然是一样的。
这个过程会一直持续下去,直到双方成功协商。
现在问题来了,万一双方随机到了相同的数字,然后循环的时间间隔也一样呢?我们可以简单计算一下出现这种情况的几率:
双方随机到相同数字的几率是 1/2047,双方选择相同时间间隔的几率是 1/4,也就是说,双方同时切换 MDI/MDI-X 标准的几率是 1/8188。
循环每大概 62ms 运行一遍,也就是说,每秒有大概 16 个循环(每次循环开始时都会重新随机一次)。那么双方在 1 秒之内始终是相同的循环时间的几率是 1/4,294,967,296 (42 亿分之一,1/2^32)。因此,二者结合,双方在一秒内始终随机到相同的随机数、且时间间隔也一样的几率是 1/8,791,798,054,912 (8.7万亿),这种事情几乎不可能发生,就算发生了,你再等一秒就行了。
在网络的物理连线上使用双绞线似乎毋庸置疑。但是,为什么呢?是什么源于让双绞线在网络布线选择中处于主导地位?
有两个主要的原因,且都与电磁干扰(Electromagnetic Interference)(EMI)相关:
如果网线需要长距离与其他各种线缆捆绑在一起布置(比如数据中心或者配电箱),以上两个特性都是非常重要的。
只要导线中有电流信号,那就一定会辐射 EMI,进而影响到周围的线缆——也就是通常所说的“串扰”。EMI 辐射可以通过额外的屏蔽装置补偿掉,但是大名鼎鼎的 贝尔先生 发明了抵消电磁干扰的绝妙方法。
他的想法是使用两根导线,其中一根发送原始信号,另一根发送与原始信号完全相反的信号。如此一来,两根线会辐射恰好反向的 EMI,也就互相抵消了。
简单解释一下,如果一根线发送 +10V 的电压,并辐射了 +0.01V 的 EMI;而另一根线同时发送 -10V 的电压,并辐射了 -0.01V 的 EMI。它们的 EMI 加起来就是 0。
在电气工程中,这两根线通常被称为“差分对”,可以用 TX+ 和 TX- 来表示。
这一发明可以实现不需要大量屏蔽的布线方案,也是当前非屏蔽线得以大量使用的原因之一。
但现在我们只回答了“双绞线”中的“双”,至于为什么还要“绞”,我们继续往下看:
即使采用了上述的“差分线”,我们也无法避开所有外部的电磁干扰。无线网络、蓝牙、卫星通讯以及手机等都会成为空间中杂散的无线电波来源。
但幸好贝尔又出现了,并设计了一种非常简单却很有效的方案以屏蔽电磁干扰。
这一设计基于 EMI 的一个基本概念:离 EMI 辐射源越近,收到的干扰越强。如果两根线交替着靠近 EMI 辐射源,它们就能吸收同样多的辐射。如下图所示:
蓝色线的初始电压是 +50V,绿线与之相反为 -50V。EMI 辐射源为图中的红圈,一圈圈向外辐射,离中心越远的圈层干扰电压越小。如果简单将图中每根线上绘制的点受到的干扰电压相加,会发现两根线都增加了 22V 的电压。
尽管上图导线右侧的电压与左侧的不同,但是两根导线之间的电压差却总是一致的,一直都是 100V。EMI 对两根导线的影响是等同的。经过简单的计算与变换,即可根据最终的 100V 电压差得到初始信号分别为 +50V 和 -50V,如下图所示:
提醒一下,以上 EMI 干扰相关电压数值被严重夸大了。实际上,正常情况下 EMI 带来的电压扰动是微伏(µV)级别的,即 1/1000,000 V。但原理依然是一样的。
上文讲到,网线中的数据是以数字信号的方式发送的,也就是一串 1 和 0 的数据流。但双绞线具体是如何发送数据的呢?我们接下来会用一个简化的模型来解释一下。
发送数据信号,本质上来说就是在某段时间内,给导线加上变化的电压。收发双方会先协商好一个时钟频率,以确定传输的每一单位的电压信号将维持多长时间。简便起见,我们称之为“位号”。在给定的时间点,每一个位号只能表示线上传输的 0 或者 1。
不同的标准会规定不同的电压等级,但由于我们简化了模型,所以不用管真正的电压是多少。但我们依然会使用 100BASE-TX 标准所规定的电压等级,即 +2.5V 和 -2.5V。
如果要在某个位号上发送比特 1,发送方会向 TX+ 线上施加 +2.5V 电压;如果要发送比特 0,就向 TX+ 线上发送 -2.5V 电压。
而 TX- 线则始终相反,比特 1 是 -2.5V,比特 0 是 +2.5V。
下表是发送 110010101110 二进制序列的相关情况:
注意上图不是网线的实体布局,只代表 TX+ 和 TX- 线上交替变化的电压信号。双绞线实际是均匀缠绕的。
就像之前讲到的,每对中的两根线上的电压总是互为相反量,一切都很整齐,且在水平方向上是对称的。
现在假设网线附近有 EMI 辐射源,我们在上表中添加一行噪声数据,然后看看最终会变成什么样:
注意到,现在这幅图已经不再对称了。两根线仍然发送相反的电压,但加了一个偏置量。
但是,接收端并不一定要完美的 +2.5V 和 -2.5V,它只需确定哪根线发送更高的电平。如果 TX+ 发送的是高电平,那么这个位号就表示 1,如果 TX- 是更高的电平,那么这个位号就表示 0。
或者更简单,如果上图中蓝线在上面,就代表 1,黄线在上面,就代表 0。
通过这种方式,接收端能一位一位地拼凑好整个数据,不管 EMI 对原始电平有怎样的干扰。可见,非屏蔽线不能消除电磁干扰,但能消除电磁干扰的影响。
我们已经详细介绍了快速以太网(100Mbps),现在我们继续讨论一下吉比特以太网(千兆以太网,1000Mbps 或者 1Gbps)。
首要的区别就是,吉比特以太网标准需要用到全部 4 对 8 根线,不像百兆网只用到 2 对。因此,在制造吉比特以太网网线时,全部 4 对线都需要交叉。
前文讲到,RJ45 有两种不同的标准:T-568a 和 T-568b。下图描绘了 4 对线都交叉它们各自的样子:
也就是说,吉比特以太网需要自动 MDI-X。所以,你可以直接在千兆网络中使用直通线,然后让网卡自动选择是否需要交叉。
吉比特以太网有两种布线标准:
此标准使用了全部 4 对线,但规定了其中两对线为 TX,另外两对线为 RX。
理论上讲,这比 1000BASE-T 更简单,但是这需要更昂贵的 Cat6 网线,而不是常见的 Cat5 或 Cat5e 网线。因此,1000BASE-TX 在实际部署中并不常见。
这是当前应用最广泛的吉比特以太网标准。它以全双工模式同时使用了全部 4 对线,也就是说每对线都可以同时用作 RX 和 TX。这是通过“回声消除”技术实现的,我们会在下一节详细阐述。
使用这种线序标准的最大优势是,你可以在现有的 Cat5e 网线上跑到千兆,而无需升级到更贵的 Cat6 网线。
1000BASE-T 经常被错误地指代 1000BASE-TX。这可能是因为在快速以太网协议中,占主导地位的标准是 100BASE-TX。另外很多时候,线缆标准也经常合起来称作 10/100/1000 BASE-TX。实际上,各个不同速率下,占主导的以太网协议分别是 10BASE-T、100BASE-TX 以及 1000BASE-T。
上节说到,1000BASE-T 标准可以在同一对线上同时发送和接收数据。在本节我们将解释这是如何实现的。首先,我们来做一个简单的类比。
你应该有过这样的经历:在跟别人通电话时,如果对方开了免提,你就能在听筒中听到自己的声音。这是因为你的声音从对方的扬声器中发出,在空间中遇到障碍物反射,又被对方的麦克风接收。这就叫做回声。
高端的电话可以从麦克风收到的声波中剔除扬声器发出的声波——这个技术就叫做回声消除。
回声消除也是吉比特以太网能够在同一对线上同时发送和接收数据的基础。基本原理就是,如果你知道你发送了什么信号,那么你就能从你收到的信号中将其剔除。
前文讲到,发送信号本质上是往导线上施加电压。反之,接收信号就是读取导线上的电压值。
如果发送方往某根导线上施加了以下电压:
1 | +0.5V, +1V, -2V, -1V |
同时,也是发送方,它在同一个导线上读取到了以下电压值:
1 | +1.5V, 0V, -2.5V, +1V |
那么,发送方可做一个减法,用读取值减去其发送的值,这样就能得到对方往这根线上加了多高的电压:
1 | +1V, -1V, -0.5V, +2V |
如此一来,同一根线就能在同一时间,同时发送和接收数据了。
再次强调,上述电压值仅仅为了解释原理,实际情况下,电压值可能完全不同,还会包含 EMI 等。同时,我们刚刚只讨论了双绞线中的一根线,另一根线仍然会承载反向的电压。
使用这种技术,全部 4 对线都可被同时用作 TX 和 RX。另外与前面几节的讨论相同,由于采用了双绞线,它们都还会消除入方向和出方向的 EMI。
读到这里,你应该对以太网和双绞线的知识点有一个宏观的理解了。这些年我们学习并整理出了这篇文章,原来看似简单的网线居然囊括了这么多技术点,现在感觉很对不起那些被我随便就扔掉的网线了。
以太网线充满了许多我们本以为理所当然的技术,但实际却很复杂。本文为了便于理解,也省略了很多细节,如果读者有兴趣可以继续研究。
]]>本文是“攻玉计划”的一部分,翻译自 https://www.ateamsystems.com/tech-blog/freebsd-vs-linux-which-open-source-os-is-superior/
FreeBSD 和 Linux,哪一个更强大?这个问题没那么简单。它们各有春秋,不能一概而论。
来自我们 A-Team Systems 的专家们有数十年这两个系统的使用经验,所以,我们将详细阐述这两个系统的优势和劣势,供你选择最适合的系统。
让我们比较一下这两个 Unix 系统的关键几个方面:
在这一点上,FreeBSD 更有优势。
这是因为 Linux 实际上并不是一个完整的操作系统,而只是一个内核。这是一个很常见的误解,因为很多用户经常把 Linux 看成是一个完整的操作系统。
各个 Linux 发行版通常会将必需的软件和库文件打包进系统,这些软件和库文件大多来自 GNU 项目,所以自由软件基金会才将 Linux 称作“GNU/Linux”。
以下是一些流行的 Linux 发行版:
关于价格,二者不分胜负。因为作为开源软件,FreeBSD 和 Linux 自然都是免费的。
译者按:在译者看来,开源并不一定意味着免费,很多开源许可证并不允许商用。当然,Linux 和 FreeBSD 是允许免费商用的。
你可能需要为某些额外功能付费,比如服务支持、硬件等。
任何人都可以免费使用、修改、分发、查阅 Linux 及 FreeBSD 的源代码。但是,任何对 Linux 所作的修改都必须公开源码。
而 FreeBSD 并不需要公开,因此,需要在产品中使用相关源码的公司,在这一点上可能更倾向于使用 FreeBSD。
FreeBSD 比 Linux 略微更安全一点。FreeBSD 项目的核心支柱之一就是安全性,并且预先安装了顶级的安全功能,所以在这一点上,毫无疑问它更有优势。
但这也并不意味着 Linux 不安全。Linux 是高度可配置的,因此可以实现你想要的任何安全特性。但是从操作系统整体角度来看,FreeBSD 的安全性更高。
如果比较硬件与架构支持度的话,Linux 绝对是占优势的。Linux 可以在许多不同的平台上运行,但是 FreeBSD 不行。所以,如果你很在乎兼容性和跨平台性,请选择 Linux。
但这也是一把双刃剑,为了能在大量不同的平台上运行,Linux 必须牺牲一部分性能以换取兼容性。而另一方面,FreeBSD 无需牺牲性能,因为它只需要在有限数量的平台上运行即可。
由于 Linux 是一个主流的系统,而 FreeBSD 不是,所以设备制造商更倾向于制造兼容 Linux 的软硬件。举个例子,如果你需要经常更新显卡驱动,Linux 会比 FreeBSD 更快获取相关更新支持。
FreeBSD 对硬件支持的短板大多集中在外设和显卡这种桌面级应用方面。但 FreeBSD 的目标场景是服务器应用,所以这并没有多大影响。
Linux 和 FreeBSD 都相当稳定可靠。但如果必须得比个高下的话,FreeBSD 会更稳定一点。这又回到了一个事实:FreeBSD 更有组织性。Linux 的稳定性可能会被用户使用的额外组件而拖累。而与此同时,FreeBSD 是一个完整的操作系统,所以它的默认配置更加可靠。总而言之,二者都不缺乏稳定性。
虽然业界没有确凿的证据证明 FreeBSD 比 Linux 的性能更优,但是大多数用过二者的用户都说 FreeBSD 在这方面更强一点。这同样归咎于 Linux 的高兼容性。FreeBSD 更精简,无需对环境做额外的判断,因此通常来说它的性能更好。
FreeBSD 的延迟比 Linux 更低。这里延迟指的是系统时钟中断发生后,到处理器开始运行代码的这段时间。但是大多数应用在 Linux 上跑得更快。
FreeBSD 使用了它自己的 BSD 许可证。该许可证允许用户免费使用该操作系统,并随意修改源码。如果愿意的话,用户也可以发布修改后的源码,或者直接闭源,BSD 许可证允许他们这么做。
Linux 使用的是 GNU GPL 许可证(GNU通用公共许可协议)。用户可在遵循该许可证限制的情况下随意修改源码。主要区别是,如果你对 Linux 源码作了修改,那么法律意义上你必须公开你的代码。
译者按:译者认为这是片面的,如果你修改代码并仅供自己研究使用,那么不需要公开代码。你只需要把源码公开给用户即可。
这个许可证既有好处也有坏处,最大的劣势就是,用户不能用 Linux 开发闭源的系统。而优势是,所有用户都可互相贡献代码,推动整个项目前进。这也是 Linux 能有这么大社区的原因。
大多数用户无需关心本节的区别,因为大多数人根本不会修改源码。但如果你想使用一个开源的系统来开发闭源的系统,请选择 FreeBSD 而不是 Linux。
从用户角度,大多数人可能认为 Linux 默认的 BASH 比 FreeBSD 的 tcsh 更强大,因为 tcsh 太落伍了。BASH 非常灵活,用户几乎可以在任何 Unix 兼容的系统上做任何事。但这也并不意味着 tcsh 一无是处,tcsh 只是学习路线更陡峭而已。当然,在 FreeBSD 上安装 BASH 也很简单。
这一方面,二者也是平手。Linux 和 FreeBSD 都采用了非常高效的文件系统。
FreeBSD 默认使用 ZFS(泽字节文件系统),这绝对是长期存储数据的最佳文件系统之一。它内置了一个磁盘卷管理器,因此允许用户在同一个存储池上创建多个文件系统。因此在发生物理故障、操作失误或者数据损坏的情况下,仍能保证数据一定的可靠性。
ext4 是大多数 Linux 发行版的默认文件系统。它不如 ZFS 那么灵活,但相当可靠。
这一轮 Linux 获胜。IBM、戴尔和惠普的服务器都直接支持运行 Linux。FreeBSD 也能在这些服务器上运行,并且有 A-Team Systems 团队可提供支持。你可以查阅 FreeBSD 的 硬件制造商 以了解当前所支持的硬件。
当考虑更新时,你需要关注两方面:更新的便捷度以及更新发布是否及时。
在便捷度方面,FreeBSD 更胜一筹。用户可以依其意愿选择更新某些组件,比如,你可以只更新某些核心组件,比如内核、源码等,或者只更新它们的子组件。当然也可以全部更新,操作非常简单。
而对于更新的及时度,Linux 表现得更好。开源公司通常有很强的动力去更新,因此,只要有需求,更新很快就能发布。FreeBSD 可能需要花更长的时间去开发、发布更新,但事实上,Linux 和 FreeBSD 经常可以同时获取相关更新,因为他们使用了同样的上游项目。
在 FreeBSD 上安装软件包很简单。FreeBSD Ports 项目包含了将近 40000 个软件源,用户或管理员可以方便快捷地安装它们。每个软件源都有针对用户实际系统的相关补丁,以确保软件能在特定平台上正常运行。
而不同 Linux 发行版的包管理工具就参差不齐了,有些非常棒,有些就很一般。以下是一些做得比较好的包管理工具:
FreeBSD 核心团队有 9 名成员,并在世界范围内有大约 500 名代码贡献者。这个团队负责调试、开发并优化主线代码仓库。大多数贡献者都是不求回报的志愿者,核心团队成员由所有活跃的贡献者每两年一次投票选出。
而 Linux 内核由 Linus Torvals 先生管理维护,他也是 Linux 的缔造者。Linus 先生对 Linux 的新功能拥有最终决定权。
FreeBSD 是一个完整的操作系统,拥有内核、驱动、文档以及各种工具。Linux 只有内核以及部分驱动,并且依赖第三方系统软件才能运行。FreeBSD 的源码使用 BSD 许可证,而 Linux 使用 GPL 许可证。
Linux 广泛支持各种硬件,而 FreeBSD 支持的硬件非常有限。Linux 也是当前市场上最流行的开源操作系统,所以不缺各种支持。FreeBSD 也有非常忠实的用户群,但远不能与 Linux 的用户群相提并论。
FreeBSD 的安全问题通常比 Linux 更少,但是差距并不大。Linux 的用户比 FreeBSD 更多,所以也会发现更多的漏洞。由于 FreeBSD 提供了完整的操作系统,所以其默认配置非常安全。
Linux 系统的安全性取决于用户的配置。由于其高度的可定制化,Linux 用户可以让他们的系统变得几乎牢不可破。
FreeBSD 提供了与 Linux 的 二进制兼容性。这允许用户在 FreeBSD 系统上安装并运行 Linux 的二进制程序。FreeBSD 上默认没有安装 Linux 的相关库文件,但可以从 FreeBSD Ports 上安装,或者手动安装。
这其中有多个原因。一方面,FreeBSD 缺乏硬件支持,这就限制了用户使用它的场景。
另一个原因是 FreeBSD 缺乏商业支持。有如 Red Hat 这样的大公司能确保 Linux 及时获取更新支持,但对于 FreeBSD 而言这是不可能的。
最后,Linux 拥有数量众多的软件,允许其发挥最大的灵活性和可用性。FreeBSD 提供了一些预编译的软件包,但仍无法与 Linux 相比。
FreeBSD 和 Linux 都需要一定的学习成本。但是,FreeBSD 相对而言更易学习使用,因为它没有那么多学习选项,例如发行版、包管理工具等等。
大多数开发者认为,比起 FreeBSD,Linux 太混乱了。对于同一个任务有无数种实现方案,并且不同的用户对应该如何选择方案有不同(且强烈)的意见。Linux 社区是一个快节奏的社区,经常经历变化。因此,很多用户更喜欢 FreeBSD 社区的一致性和条理性。
总的来说,FreeBSD 通常比 Linux 更快。这主要是因为它是一个完整的系统。此外,FreeBSD 的延迟比 Linux 低,也就意味着它能更快处理输入。有如网飞、苹果和思科之类的公司会采用 FreeBSD 以获取这种处理速度优势。
Linux 也能获得类似的速度,但是,这取决于你的配置。还值得注意的是,大多数应用程序在 Linux 上运行得更快。因此大多数超级计算机会使用 Linux 而不是 FreeBSD。
FreeBSD 和 Linux 都可作为开源用户的选择。最主要的区别就是,FreeBSD 更完整,更标准化,而 Linux 只提供了内核及驱动,需要第三方软件支持。
如果想要尽可能少地配置系统,FreeBSD 是更好的选择。但是,Linux 提供了更多的自定义选项,对于想要定制系统的人是个更好的选择。另外,如果你有硬件平台限制的话,Linux 的支持性可能更好点。
如果你喜欢紧跟技术潮流,Linux 的新技术、新特性和更新速度肯定会让你满意。如果稳定性、性能和安全性对你来说更重要,FreeBSD 也许更适合你。
]]>本文是“攻玉计划”的一部分,翻译自 https://stackoverflow.com/questions/35465557/how-to-apply-color-in-markdown
我想用 Markdown 记录文字信息,但我搜了一圈 Google,发现 Markdown 不支持修改字体颜色。而且 StackOverflow 和 GitHub 的 Markdown 编辑模式也不支持指定文字颜色。
有什么办法可以在 Markdown 里指定文字颜色吗?
太长不看系列:
Markdown 自身并不支持色彩配置,但你可以在 Markdown 中添加 HTML 代码,例如:
1 | <span style="color:blue">这是**蓝色**的文字</span> |
以下是长回答:
根据官方的 语法规则:
Markdown 只有一个用途,就是作为编写网页的一种语法格式。
Markdown 不能取代 HTML,甚至不能实现 HTML 的大部分功能。它的语法很简单,只能覆盖很小一部分的 HTML 标签。Markdown 并不是为了让你更方便地插入 HTML 标签。我的观点是,HTML 标签已经很方便了,而 Markdown 是为了让人更容易读、写、改。HTML 是用于发布的格式,而 Markdown 是给人写的格式。因此,Markdown的语法格式只用来处理可以用纯文本表达的信息。
对于任何 Markdown 未实现的功能,直接插入 HTML 代码即可。
由于 Markdown 并不是用来发布的格式,修改字体的颜色已经超出了 Markdown 的处理范围。但你仍可以插入裸的 HTML 代码(因为 HTML 是发布级的格式),例如以下 Markdown 文本:
1 | 包含 <span style="color:blue">*蓝色* 文字</span>的 Markdown 语句。 |
将会转换为以下 HTML 代码:
1 | <p>包含 <span style="color:blue"><em>蓝色</em> 文字</span>的 Markdown 语句。</p> |
目前,StackOverflow (也许 GitHub 也是)会把 HTML 代码原原本本地显示出来(因为安全性考虑),因此你无法在这些地方实现文字颜色的功能,但你可以在 Markdown 的任何标准实现中使用。
另一种解决方案是,直接使用 Markuru 的非标准属性表。此标准后续被 其它 一些人(可能还有其他类似理念的方案,比如 pandoc 中的 div 和 span 参数)继承开发。如果用了这种方案,你就可以为一段文字或者行内元素配置一个类,然后用 CSS 给这个类定义色彩属性。但显然,你必须使用支持这些非标准方案的编辑工具,并且这样写出来的文档也没法移植到其他系统上。
如果你不想嵌入 HTML,只想用纯净的 Markdown 语句,可以尝试添加 emoji 以便强调指定语句。比如:⚠️警告⚠️,🔴重要❗🔴 或者 🔥新功能🔥。
尽管 Markdown 不支持文字颜色属性,但你可以用 CSS 重定义一些格式标签,以便用它们来修改文字颜色。当然,你可以选择是否保留这些格式标签的原有属性。
例如:
1 | // 重置标签属性 |
然后,在 Markdown 文本中这样使用:
1 | ~~这是绿色~~ |
可以换个思路,你可以用各种颜色的 Unicode 字符以满足相关需求,比如 🔴,U+1F534(大红圈)。
举个例子,在我 GitHub 里的硬件项目中,我会用以下的字符以注明接线的颜色:
1 | 🔴 红色: +5V |
这也许能帮到你,你可以直接复制粘贴上述字符到你的文档中,或者直接在网上搜例如“Unicode 紫色方块”之类。当然,它们也叫做 emoji。
]]>本文是“攻玉计划”的一部分,翻译自 https://randomnerdtutorials.com/esp8266-pinout-reference-gpios/
本文旨在介绍 ESP8266 的引脚定义、引脚功能及如何使用它们。
ESP-12E 模块拥有 17 个 GPIO 引脚。但在各个开发板上,ESP8266 芯片的 GPIO 引脚并不一定全部引出,而且某些引脚不建议使用,某些引脚有非常特殊的功能。
本文将指导你如何正确使用 ESP8266 的各个 GPIO,避免用错引脚而浪费时间。
下图阐述了 ESP-12E 模块的引脚定义。当你的项目使用裸 ESP-12E/F 模块的时候,可以参考此图。
🔵注意:某些开发板可能不能使用全部的引脚,但相同的引脚在不同的开发板上,功能肯定是一样的。
当前市场上有很多不同的 ESP8266 模块/开发板,它们的形状、大小、可用 GPIO 数目各不相同。但最常用的是 ESP-01(S)、ESP-12E/F、NodeMCU 开发板以及 Wemos D1 Mini 开发板。你可以自己搜索这些开发板模块的区别。
如果你在用 ESP-01(S) 的板子,可以参考下图的 GPIO 引脚定义。
ESP-12E NodeMCU 开发板的引脚定义如下图所示。
Wemos D1 Mini 开发板的引脚定义如下图所示。
ESP8266 的外设包括:
需要注意的一点是,ESP8266 开发板上丝印的引脚号,并不是芯片真正的 GPIO 编号。比如,D0 是 GPIO16,D1 是 GPIO5。
下表说明了 ESP8266 开发板上丝印的引脚号与实际 GPIO 编号的对应关系,并提醒你哪些引脚在使用时需要注意。
绿色标记的引脚可以随意使用;黄色标记的引脚可以使用,但需要注意它们在芯片启动时的影响,可能带来意外的问题。红色标记的引脚不建议用作输入或输出功能。
丝印标签 | GPIO | 可作为输入 | 可作为输出 | 备注 |
---|---|---|---|---|
D0 | GPIO16 | 不可用于中断 | 不可用于 PWM 或 I2C | 🟠启动时为高电平 用于从深度睡眠中唤醒 |
D1 | GPIO5 | 🟢是 | 🟢是 | 通常用作 SCL (I2C) |
D2 | GPIO4 | 🟢是 | 🟢是 | 通常用作 SDA (I2C) |
D3 | GPIO0 | 已被上拉 | 🟢是 | 与 FLASH 按键连接,如果拉低则会启动失败 |
D4 | GPIO2 | 已被上拉 | 🟢是 | 🟠启动时为高电平 连接板载 LED,如果拉低则会启动失败 |
D5 | GPIO14 | 🟢是 | 🟢是 | SPI (SCLK) |
D6 | GPIO12 | 🟢是 | 🟢是 | SPI (MISO) |
D7 | GPIO13 | 🟢是 | 🟢是 | SPI (MOSI) |
D8 | GPIO15 | 已被下拉至 GND | 🟡是 | SPI (CS) 如果拉高则会启动失败 |
RX | GPIO3 | 🟡是 | 🔴RX 引脚 | 🟠启动时为高电平 |
TX | GPIO1 | 🔴TX 引脚 | 🟡是 | 🟠启动时为高电平 启动时的调试输出引脚,如果拉低会启动失败 |
A0 | ADC0 | 🟢模拟输入 | 🔴禁用 |
接下来的篇幅将更详细地介绍 ESP8266 GPIO 引脚的功能。
GPIO6 到 GPIO11 通常用于连接 FLASH 芯片,所以,不推荐使用这几个引脚。
如果某些引脚被拉高或者拉低,ESP8266 可能会启动失败。下表是部分引脚在启动时的状态:
以下引脚在启动时会输出 3.3V 的高电平。如果你在这些引脚上接了继电器之类的外设,可能会带来一些问题:
此外,其他引脚(除了 GPIO5 和 GPIO4),在启动时会输出低电平信号,同样可能带来问题。你可以阅读 此文章 以详细了解各个 GPIO 在启动时的状态。
🟢如果需要控制继电器或功率管,GPIO4 和 GPIO5 是最安全的引脚。
ESP8266 只有一个引脚支持模拟输入,此引脚叫 ADC0,丝印上常标记为 A0。
如果使用 ESP8266 裸芯片(ESP-12E/F)的话,此引脚的电压输入范围为 0-1V。如果使用了 NodeMCU 之类的开发板,那么电压输入范围就是 0-3.3V,因为开发板上已经集成了分压器。
大多数 ESP8266 模块均有一个内置的 LED,通常连在 GPIO2 上。LED 亮灭的逻辑是反向的,GPIO2 为高电平时,LED 熄灭;GPIO2 低电平时,LED 亮起。
当 RST 引脚被拉低时,ESP8266 将被复位。按开发板上的 RESET 按键同理。
当 GPIO0 被拉低时,复位 ESP8266,芯片将进入 bootloader 模式。按开发板上的 FLASH/BOOT 按钮同理。
GPIO16 可被用于从深度睡眠中唤醒 ESP8266。要实现此功能,需要将 GPIO16 连接在 RST 引脚上。关于如何实现深度睡眠,请搜索并参考 Arduino 官网上的相关案例。
ESP8266 没有硬件 I2C 引脚,但可以用软件模拟,所以你可以使用任意引脚实现 I2C。通常我们会使用以下引脚:
ESP8266 上的 SPI 引脚如下:
我们可以在 ESP8266 的所有引脚(GPIO0 至 GPIO15)上软件实现 PWM 功能。ESP8266 上的 PWM 有 10 位精度。关于如何实现 PWM 功能,请搜索并参考 Arduino 官网上的相关案例。
ESP8266 的所有 GPIO 引脚均支持中断,除了 GPIO16。相关案例请搜索并参考 Arduino 官网上的相关案例。
希望本文能解决你对 ESP8266 GPIO 的相关疑惑,祝好!
]]>众所周知的背景:
所以干脆 DIY 一个。
我想做出这样的效果:打开 APP 后,直接显示苏康码,滑动屏幕可切换到行程码,不需要任何多余的点击动作。
我没有任何 APP 开发经验,所以相当于新手。因为最近用 C# 和 .NET 框架比较多,经 V2EX 网友提醒,我选择了 Xamarin 框架。据说如果新手想快速尝试跨平台 APP 开发,用 flutter 比较好,但是……whatever,支持一下微软,及其宇宙第一 IDE。
既然苏康码本质上是网页,而且我在朋友圈了解到,可以获取到直链而且是不需要认证的,只要 token 对就行了,那就简单了。
于是我决定使用 Fiddler 抓包,大致步骤就是:配好 Fiddler 的监听端口,然后保证电脑和手机在同一个局域网内,手机在 WiFi 设置里配置好 Fiddler 的代理。
测试的 APP 是苏周到,不出所料,苏康码链接是 HTTPS 的,想解密只能在手机上安装一个证书然后中间人了。
导出 Fiddler 的证书并复制到手机上,MIUI 安装证书的步骤也很简单,记得在抓完包之后删除这个证书就好。
然后就可以解密 HTTPS 流量。理论上,对于现在的 Android 版本,APP 可以选择不信任用户安装的证书,但还好,苏康码并没有采取这样的机制。
解析出来的苏康码的直链很简单,就是 https://jsstm.jszwfw.gov.cn/jkmIndex.html?token=xxxxxxxxxxxxxxxx&uuid=xxxxxxxxxxxxxxx 这样的格式,直接访问就可以看到自己的苏康码界面。
行程码直链更简单,直接就可以搜到: https://xc.caict.ac.cn/ 。有趣的是,行程码居然是用 Vue 框架做的,如果只是普通的 HTML 表单页面的话,我也许会做一个自动发验证码查询的功能。
安装移动端开发相关 SDK 后,启动宇宙最强 IDE,新建一个空项目叫 ShuangShuangMa
(随便起一个名字,双双码),然后面向 Google 编程……基本上只要查一下怎么使用 WebView 以及如何实现滑动切换页面就好了。
代码非常简单,xaml 页面如下:
1 |
|
C# 逻辑如下:
1 | using System; |
部分解释:
MainActivity.cs
中添加以下代码以便把返回按钮当 Home 键用:1 | public override void OnBackPressed() |
当然,应用安装后得关闭电池优化、锁在后台,毕竟被清理掉之后又得重新认证行程码。
至此,APP 完成。
效果见下面的视频:
话说,本来想着 Xamarin 是跨平台的,准备给玲玲的 iPhone 也整一个的,但无奈意识到自己没有 Mac,作罢。
]]>公司产品采用了 Xilinx Zynq 7z010 芯片,用于运动控制以及网络通讯。两周前,测试过程中发现网络通信会小概率出错,TCP 收到的数据 CRC 校验失败,无法稳定复现。
设备平台概述:
TCP 是二进制数据流,每个包的长度不固定,应用层也许会写错。于是我修改了应用层的处理方案,手动构造了定长的数据包,虽然会导致 TCP 流量大幅上涨,但是逻辑看起来更清晰。
然而,修改后,似乎由于流量变大了,原来小概率出现的错误,现在大概率会出现!这也给 Debug 带来了有利的一面。
但是这个怀疑方向很快就被否定了,因为我用了 TCP 协议,理论上只可能超时,不可能出错。
lwip 有多个 TCP API,之前用的 Socket API,我尝试换成了 RAW API,但是问题依旧。
在调试的过程中,我尝试在网络链路的每一层数据打印出来,惊奇地发现,在数据链路层,数据是正确的!然而 lwip 的代码冗杂且数 MB 数据中才会出现几个错误位,于是我暂时没有考虑一层层分析代码。
这样 Debug 就很简单了。我关闭了所有其他的线程,不出所料,Bug 消失了。
一点点放开线程,发现是一个运动控制的硬中断造成的 Bug。
然后再“二分法”排除代码,结果排除到最后,仅仅是一行代码:
1 | // b, c 也为 long long |
这让我大跌眼镜,因为实验证明,把这句话删了,TCP 通讯就正常了。
更加让我迷惑的是,把上述语句改下,同样也没问题了:
1 | long long a = b * c; |
进一步定位:我在另一个线程中添加了浮点运算,并把这个有影响的中断关闭,TCP 通讯同样出问题了。
就此,几乎可以确定是浮点数运算造成的问题了。
一句话描述问题:在中断或某个线程中进行浮点数操作,会导致另一个 TCP 通讯线程数据出错。
说实话,我当时也没法理解其中的联系。
只不过我们用的芯片自带双精度 FPU(浮点运算单元),也许是 FPU 的问题?
关键词 lwip tcp receive wrong data
,zynq float process corrupt memory
等关键词,都没有找到有价值的解决方案。
果然用微信联系的技术支持不靠谱,上午说帮忙复现,下午就没信了。
只可惜他们都是互联网界的大佬,只有我在嵌入式开发领域摸爬滚打,他山之玉难以攻石。
发了帖子 在这里。
V 站网友给了非常有价值的线索:
正在计算浮点数的时候,刚好发生了 systick 线程切换,但是线程切换过程中,没有保存 /恢复浮点寄存器
;“Some GCC libraries optimise memory copy and memory set (and possibly other) functions by making use of the wide floating point registers. Therefore, by default, any task that uses functions such as memcpy(), memcmp() or memset(), or uses a FreeRTOS API function such as xQueueSend() which itself uses memcpy(), will inadvertently corrupt the floating point registers.”
真可谓一针见血,TCP 协议栈中大量使用了 memcpy,而 memcpy 又使用了 FPU 的寄存器,极有可能在 TCP 处理数据的过程中,另一个中断来了,进行了浮点运算并修改了 FPU 的寄存器,以致 TCP 数据出错。
同样根据网友的指点,看了这篇文章 Using FreeRTOS on ARM Cortex-A9 Embedded Processors,原来 FreeRTOS 自身已经考虑了 FPU 与上下文切换相关的问题,只是要我们将 configUSE_TASK_FPU_SUPPORT
这个宏定义为 2 即可。
花了些时间进行 FPU 寄存器相关的搜索,依照 这篇文章 ,对 FPU 的寄存器做了相关处理,总结起来就三行代码:
在中断响应函数开头添加以下代码:
1 | __asm("VPUSH {d0-d15}"); // FPU 寄存器入栈 |
在中断响应函数末尾添加以下代码:
1 | __asm("VPOP {d0-d15}"); // FPU 寄存器出栈 |
FreeRTOS 启用 FPU 支持相关宏:
1 |
至此,问题解决。
]]>重新加上了 Disqus 评论系统,翻译了一个树莓派引脚定义网站,换了企业邮箱服务商,部署了一个站点监控系统,开始搞 nextcloud 中文论坛……随便聊聊最近在本站折腾的那些东西。
本站博客一直用的是 hexo,评论系统一开始也是用的 Disqus,后来不知道为啥就把评论系统给删了(可能是因为被墙了没意思?还是因为换了主题不支持啥的)。评论系统删了以后,又脑抽用 flarum 搭建了一个论坛,然后每篇博客前面都加一个对应的论坛讨论地址……这个方案被 PM 学叔给喷了,因为谁会为了评论,再去注册一个你的论坛账户呢?所以前几天把论坛给删了(话说也只有瑞辅一个人评论过一次,哈哈)。
Disqus 评论系统可能是在 hexo 上最好用的评论系统了,谁让 hexo 自己本身就是一个静态页面呢。但问题是 Disqus 被墙了,我得提醒读者,本站是有评论系统的。很久以前看到奶冰的博客,也是用的 Disqus,他是自己加了一个按钮,提醒用户点击加载 Disqus 评论组件。于是时隔几年我把这个想法抄过来了。
一开始感觉做这个按钮好复杂啊,因为自己几乎没有前端开发的经验。但是随便翻了翻我用的这个 aircloud 主题,发现源码改起来还是挺容易的,就强行加了一个按钮(话说改的方法我也上传到我 fork 的这个仓库里面了,https://github.com/Villivateur/hexo-theme-aircloud。
除了改了评论系统,我也魔改了其他小东西。我有点洁癖嘛,而且自从上次 jsdelivr 被拔网线的事情之后,我觉得静态资源用其他的站点托管都不太稳定,于是把 aircloud 里面用到的 js 和 CSS 都下载并重新托管在了自己的服务器上。
aircloud 还提供了浏览量计数功能,一看也是加载了第三方的 JS,算了不要了,有点洁癖。
很早就了解到过一个做得很棒的树莓派引脚定义查询网站 pinout.xyz,而且已经有人翻译成了法语、德语、土耳其语啥的。我一直有很强烈的翻译欲望,现在终于找到了一个适合翻译的(之前没人翻译过、数据量不大),于是就开始了。
按照原作者给的翻译指引翻译了几个页面,但是感觉不过瘾,于是把本不该翻译的也翻译了(比如页面左下角的树莓派小图,还有生成脚本里面的一些细节),看来是没法全部提交 PR 了。故又 fork 了一个纯中文版的仓库,地址 https://git.vvzero.com/villivateur/pinout.vvzero.com ,用于部署 https://pinout.vvzero.com 。按照翻译指引的仓库 https://github.com/Villivateur/Pinout.xyz 只用来提交 PR。
腾讯企业邮箱是越来越恶心了,强行给你绑企业微信,还各种限制,不用微信登陆就强制改密码,算了,终于忍不了弃用了。V 站网友推荐了 zoho 邮箱,试了下感觉不错,于是给自己和玲玲买了两个账户,国区的,一年一共 100,完全可以接受。
目前发现 zoho 邮箱有两个问题:
也是看到奶冰的网站,有个站点监控的玩意,用了 uptimerobot 的服务,试了下挺好玩,于是也部署在了 https://status.vvzero.com
算是闲得蛋疼吧,感觉没人做 nextcloud 中文论坛,但我用 nextcloud 确实很多,就“抢先”搞了,虽然目前没什么内容。https://www.nextcloudcn.com 这个域名还是我抢注的,之前一个人刚好到期。没备案,所以只能托管在香港,套个 cloudflare。
至于运营就看情怀了,希望明年还想续费这个域名……
]]>Mapuino 是一个简单的摆件,或者叫“玩具”。你可以在自己的个人博客、主页或者任何可以插入个性代码的社交网站(如 V2EX)上添加一行 URL,然后就可以在 Mapuino 上观赏全国哪些地方的人正在访问你的网站。
Mapuino 不是生产力工具,它功能单一,仅供娱乐。但它真的可以给你的生活带来一些小乐趣。
2017 年秋学季,我上大二,有幸加入学校的学生 IT 创新创业区,并认识了 suruifu 同学,当时我所在的部门叫“物联网创新区”。圣诞前夜,suruifu 同学在创新区内给我分享了一个外国小哥的 youtube 视频。视频中,外国小哥做了一个圣诞树,神奇之处是,只要有人 ping 他的电脑 ip,圣诞树上就会随机亮起一个 LED。很多人一起 ping 的时候,圣诞树就会闪闪发光。
suruifu 同学感慨:“这才是物联网!”
而后,到了今年,一个月以前,我做了第一个小摆件 Topuino。
用同样的技术栈,我又做了 Mapuino。
Mapuino 与 Topuino 类似,在配置之后,会连接 Wi-Fi 并从服务器获取数据,在每个周期内(比如 1 分钟),所有在上一个周期访问过你网站的用户,其所在省级行政区的 LED 将会亮起。
硬件部分与 Topuino 非常类似,采用 ESP8266 作为 MCU,TM1638 作为 LED 驱动。
Mapuino 会以 1 分钟为周期向服务器发起请求,服务器返回上一个周期哪些地区有用户访问了指定 URL。此 URL 可以嵌入在任何网页中,比如通过 JS 发起请求,或者假装是一个 img 标签,或者也可以用各类站长测速工具直接 DDOS 这个 URL……
服务端直接解析访问此 URL 的 IP 所在地(目前使用了高德的 API),并临时存储。
硬件端: https://github.com/Villivateur/Mapuino
服务端: https://github.com/Villivateur/MapuinoServer
我又有其他点子啦,下一个做啥呢?
]]>我做了一个用来监控服务器的桌面小摆件
Topuino 是我 DIY 的一个桌面小摆件,可以实现通用服务器或计算机的数据监控,包括 CPU 占用、RAM 占用、两个硬盘的可用空间、硬盘读写速度、网络 IO 速率。
在 Linux 系列服务器上,我们通常使用 top 命令查看 CPU 内存占用,我最初的设想也是将 top 命令实物化,这就是 Topuino 中 Top 的由来。
在选型的时候,为了兼顾开发效率和成本,我选用了大名鼎鼎的 ESP8266 单片机,配合了 Arduino 开发框架,Arduino 则是 Topuino 中 uino 的由来。
先看图解:
附上原理图:
PCB 打样交给专门的厂家,回来自己焊。
你愿意在办公桌上放一个监控服务器的小摆件吗?至少,我做出来之后,很喜欢,就像看着一只猫一样。
另:ESP8266 的代码初步开源在 https://github.com/Villivateur/Topuino ,供大家参考。服务器端代码因为太简单且写得太丑,以后再说吧~~
]]>PlatformIO 目前只是玩具,单片机开发还得用 Keil
好久不碰单片机,现在想搞个项目,选型 STM32xxxxxx,想找一套“现代化”的 IDE,于是找到了 PlatformIO。
刚开始很新奇很激动,VSCode 开发环境很友好,各种单片机型号、库很丰富,而且 STM32 可以直接用 Arduino 开发,各种一键式部署。最主要的是商用免费,差点就选用了。
但是问题很快就出现了,Arduino 框架对于底层的封装太完美,我甚至不能方便地修改 SPI 或者 I2C 的引脚,而且 GPIO 读写速度也相较使用 CMSIS 慢很多,STM32duino 虽然仍然在发展,但是,我认为还处在“玩具”的阶段。
如果抛弃 Arduino 框架,去使用 CMSIS ,那也太不方便了,而且 STM32 标准库在 PlatformIO 里面目前居然只支持很少几款芯片(F10x 系列全系不支持)。如果我要用 FreeRTOS,FreeRTOS 官方目前也没有适配 PlatformIO。
最终还是回到 Keil,花钱的才是最好的。
]]>互联网是有记忆的,在此,我就以计算机为担保,依网络见证!
]]>要读懂此文章,你需要了解对称加密、非对称加密的基本概念,并了解证书签发的基本流程。
很容易理解,CA 也有自己的公钥和私钥。
openssl genrsa -des3 -out CAPrivate.key 4096
这个命令会生成一个私钥 CAPrivate.key
,并且必须要填写私钥的密码。不要奇怪这里只有一个私钥,其实公钥也保存在这个文件里了。
openssl req -x509 -new -nodes -key CAPrivate.key -sha256 -days 3650 -out CAPrivate.pem
根证书,顾名思义,肯定是自签发的。这个证书待会需要安装到你的终端设备里面,不然靠这个根证书签发的其他证书不会被信任。
这个命令里面需要填写很多信息,按照实际填写就好。
至此,作为一个简单的 CA,所有的文件都已经齐全了。
这个私钥与 CA 无关,是待签发的下一级证书。这一步和下一步可以在另一台机器上完成,然后把文件传给保存 CA 信息的机器就好。
openssl genrsa -out example.key 4096
可以理解为一个待发送给 CA、为你签发证书的一个请求。
openssl req -new -key example.key -out example.csr
同样,这里需要填写很多信息,需要注意的是 Common Name
这个项目,如果你的证书是给 https 用的,这里就填你的域名。
openssl x509 -req -in example.csr -CA CAPrivate.pem -CAkey CAPrivate.key -CAcreateserial -out example.crt -days 365 -sha256
CAPrivate.pem
,比如 Windows、Android,某些浏览器必须单独安装证书。example.key
和 example.crt
作为 HTTPS 服务(比如 Nginx)的私钥和证书,写好配置文件。本文供初学者学习,供大佬批判。
很久很久以前,当我参加 NOIP(信息学奥林匹克竞赛)的时候,老师是这么讲补码的:
int 型数据的最高位是符号位,符号位为 0 就代表这是正数,为 1 就是负数。但是,+0 和 -0 理应是同一个数,但在二进制中却表示成了两个不同的数(以 8 位为例,二进制表示): 00000000 和 10000000。所以,我们引入了补码,补码就是,对负数而言,符号位不变,其他位取反,然后再加 1。于是, -0 的补码就是 10000000 -> 11111111 -> 00000000 与 +0 一致了。
其实当时我就该意识到,仅仅为了 0 这一个数便创建了“补码”这个概念,未免太浪费了。我最近看了 CS: APP 这本书,才进一步理解了补码。
补码,就是为有符号整数而创建的概念。对于无符号整数,是不存在“补码”的概念的。我们先看一个无符号数 00100101,它是怎么转换成十进制的?加权求和,0×2^7+0×2^6+1×2^5+0×2^4+0×2^3+1×2^2+0×2^1+1×2^0=37
;无符号数 10000011,1×2^7+0×2^6+0×2^5+0×2^4+0×2^3+0×2^2+1×2^1+1×2^0=131
。
对于有符号数呢?假如我们不用补码,那么有符号数 10000011,就是 -(0×2^6+0×2^5+0×2^4+0×2^3+0×2^2+1×2^1+1×2^0)=-3
。人这么算起来是挺舒服,但是计算机会很难受,凭什么我最高位的权值没了?只能做符号?
然后我们试试补码。10000011 的补码是 11111101,如何用补码求它的十进制呢?其实这跟无符号数是一样的,只不过,最高位的权值,不是 2^7,而是 -2^7。求值:1×(-2^7)+1×2^6+1×2^5+1×2^4+1×2^3+1×2^2+0×2^1+1×2^0=-3
,是不是很神奇?
对于正数而言,就更简单了,与无符号数一致。
计算机只能做加法(不是),所以,我们看看用补码做加法,有什么好处。
先计算 -13+10 吧,很简单的二进制竖式加法:
7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
---|---|---|---|---|---|---|---|
1 | 1 | 1 | 1 | 0 | 0 | 1 | 1 |
0 | 0 | 0 | 0 | 1 | 0 | 1 | 0 |
1 | 1 | 1 | 1 | 1 | 1 | 0 | 1 |
11111101 即为 -3 的补码。
再算一个,-8+9:
7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
---|---|---|---|---|---|---|---|
1 | 1 | 1 | 1 | 1 | 0 | 0 | 0 |
0 | 0 | 0 | 0 | 1 | 0 | 0 | 1 |
0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 |
神奇吗?最高位的 0 不见了,变成正数 1 了。
补码,就是计算机内部有符号数的存储方式,我们不要认为补码是由原码“转换”而来的,补码本来就代表了实际的数字,11111101 == -3,就这样。
]]>迫于不能浪费宿舍联通宽带的公网 IP,我用树莓派搭建了一个 NAS,使用 Samba 提供访问。但是,由于运营商限制,入站和出站的 139、445 端口都被封禁(对!你不能访问其他机器的 445 端口!),这样做只能让同一个局域网的服务访问。我尝试修改了端口号,把本地的 445 端口映射到公网的其它端口,算是可以给大部分 Samba 客户端使用了(比如安卓手机)。但是,Windows 的 Samba 客户端,并不支持设置端口号(如果在文件管理器地址栏输入 \\a.b.c.d:xxx
将会被认为是 WebDAV 协议)。
网上某些教程说,在 Windows 本地设置端口转发,把访问本机 445 端口的流量转发至你的 Samba 服务器端口。但是,这样做需要关闭 Windows 自己的 Samba 服务器,会导致网络共享、网络打印机等很多功能无法使用,导致莫名其妙的问题,所以不推荐。
但是可以换个思路。
既然不能使用本机(127.0.0.1)做转发,那么为什么不使用本地网络中其他的机器进行数据转发呢?一开始我想在本地网络中加一个树莓派之类的小主机,但觉得这样太累赘了。虚拟机也是独立的机器,我觉得一样有效。
所以,只要在虚拟机里面装一个反向代理应用(Nginx),把发往虚拟机 445 端口的流量转发到 Samba 服务器,然后使用 Windows Samba 客户端访问这个虚拟机,就等于访问 Samba 服务器。
这里,我使用了 Windows Hyper V,创建了 Ubuntu 20.04 Server 虚拟机(直接下载官方 ISO),然后使用默认交换机作为虚拟机的网络。
启动后,安装系统,然后除了更新镜像源、安装 Nginx,什么都不用做。
1 | sudo apt update |
装好 Nginx 后,修改配置文件:
1 | vim /etc/nginx/nginx.conf |
添加一个 stream 模块,大致像下面:
1 | http { |
然后重启 Nginx:
1 | sudo nginx -s reload |
转发的模块就做好了。
然后,再在 Windows 中打开 \\<虚拟机的ip>\<samba 路径(可选)>
就完成了。虚拟机 ip 可以在虚拟机里面用 ifconfig 命令查看。
也许可以用 docker 实现,但我还没想好怎么搞。
]]>要想读懂本文,你需要:
本文面向的是需要使用高性能计算设备,但是身边只有低性能PC机的群体。最近由于 NCP 疫情,出不了门,返回不了工作地,想必不少人的高性能计算设备(好电脑)没带回家,但是,肯定也有人跟我一样,受不了笔记本电脑的龟速。
我的配置需求是,能够流畅运行安装多个插件的 VSCode、能够同时打开数十个 Firefox 标签页、能够快速完成 node 项目构建。但是我身边只有一台五年前的 intel NUC (i3-4010U, 4GB RAM)。
在详细了解了各大云服务商的云计算平台后,个人排除了华为云(弹性计算服务价格较高、云桌面售罄)、腾讯云(云计算服务类别过少)、天翼云(云桌面需要安装指定 APP 且性能不满足要求),决定使用阿里云的云计算服务。
经过权衡,我决定使用阿里云 ESC “抢占式实例”付费模式下的“突发性能实例”。为什么这么选?
因为没钱……
开玩笑的。我觉得这是我需求下的合理选择方式。为什么选择“抢占式实例”?首先,我们复工的时间还是个未知数,而且可能随时就不想用这个云桌面了。“抢占式实例”是按量付费的一种,也就是,用多长时间给多少钱。并且,相对于按量付费,有相当大的折扣。“抢占式实例”的最大问题在于,这是竞价模式。也就是说,当别人出价比你高的时候,或者阿里云供给紧张而你又给钱给得不够的时候,它会自动帮你释放。我了解的是,在释放前5分钟,阿里云会有提醒。为了尽量避免实例被自动释放,我选择了“使用自动出价”,也就是说,系统会每小时自动判断当前时间该实例的价格,并选择一个高于市场均价的价格进行付费。但是,这并不是万无一失,阿里云在供给紧张的时候,仍然会将实例释放。所以,在处理重要数据时,应该随时备份。我的处理方法是,随时将代码提交到我的 Git 仓库。
如果要保证不会被释放,建议使用包年包月制。
为什么使用“突发性能实例”?因为个人电脑与服务器不同。个人电脑不会时时刻刻占用大量 CPU,CPU使用率是离散化的,所以 CPU 的使用积分,我觉得是用不完,25% 的使用基线,完全够用。
哎,目前好像国内也只有阿里云能做出“抢占式实例”和“突发性能实例”。
其他的配置就简单了,区域选择靠近你的(不同地区的价格好像差别挺大),镜像选择 Windows Server,另外,SSD 是很关键的,我觉得现在已经没有多少人能忍受机械硬盘的龟速了。
在下一个页面配置网络,为了保证远程桌面流畅,按使用流量计费,带宽拉满!
最终,我的配置如下:
这样的话,实例价格为 0.412 元每小时(我选的是上海区的,其他区的可能更便宜,在深夜、早上也会更便宜),流量费用为 0.8 元每 GB。算一算,一天大概要 10 元,一个月大概要 300 元,是不是还是有点贵?没关系,继续看。
现在我已经启动了这个实例:
我还想更便宜。
我想你一定不可能一天24小时都在用它,用它的时候也一定不会一直占满 CPU。关键是,我们这是 Windows Server,跟家庭版、专业版、企业版什么的都不一样,它支持多个用户同时登陆!所以,我觉得,如果有信任的人选,完全可以合租。
阿里云真的是神奇的存在,在 ECS 管理界面,选择停机,竟然可以停机不收费!
实际上也不是完全不收费,硬盘和弹性公网 IP 仍然是收费的。但是,与停机后仍然保留CPU、内存相比,价格大幅降低。也就是说,我们在每天晚上,完全可以关机并选择不收费,可以节约一大笔。如果想要一直使用同一个 IP,可以选择绑定弹性公网 IP。
我觉得,可能 8GB 内存已经够我用了,另外,青岛区的实例好像每小时能更便宜一毛钱……
在体验之前,再确保一下:该实例网络安全组,需要放通 3389 端口(TCP 和 UDP 都要放通)。
打开本地的远程桌面客户端试试吧!
网络方面,我是江苏电信网络,连接上海区的 ECS,延迟很小,可以忽略,而且画质很清晰,暂时没有什么画面卡顿。至于下行网络,由于这是阿里云的专线,比家用运营商网络好太多,下载速度嗖嗖的,不管国内外。
计算性能方面,在我本地机器上,VSCode 的 Python 插件,进行一次文件错误扫描需要 5 秒左右,而这台云桌面,只要 1 秒。
操作系统方面,Windows Server 比 Windows PC 简洁很多,没有乱七八糟的服务,但也没有缺少日常开发所需的重要组件。可能会有点不一样,但是如果出问题,一般能很快解决。比如我在安装 Python 时出错,Google 一下便知要直接以管理员身份打开。
以下截图自我的云桌面。
我正常使用了一天,晚上停机不收费,消费如下:
可见,我一天大致消费5元。
确实不是很贵,可行性也很高。假如有模型渲染需求,甚至可以绑定个显卡(
抢占式实例也不是很可怕吧?我的实例目前没被回收。
另外,有人想跟我合租吗?
]]>直接看步骤的话,在最下方。
Windows Terminal 虽然还处于预览阶段,但是也出来很长一段时间了。它的历史使命,也许就是让原生 Windows 也能有一个像样的命令行环境。以前我一直在用 Cmder,但是 Cmder 的启动速度确实不敢恭维,而 Windows Terminal 启动确实很快。相比 Cmder, Windows Terminal 还缺少很多功能,不过以后应该很快也会补上。
我想尝试使用 Windows Termimal 进行开发。Windows Terminal 默认可以使用 PowerShell
、cmd
、wsl bash
作为脚本工具。既然是在 Windows 环境下嘛,还是得尊敬一下 Windows PoweShell 的。初次使用,我觉得 PowerShell 跟 Cmder 用起来,最不方便的一点就是,我在 Cmder 里面设了很多的 Alias,也就是通过修改 config/user_aliases.cmd
写一串 <alia>=<xxx> <xxx>
来实现的。
但是,PowerShell 如何实现命令的别名设置呢?
如果搜索关键词 windows powershell set user alias
,通常谷歌会给出微软官方文档,但是这个文档只是告诉我们如何在脚本里面设置临时的别名,如果要设置永久别名,该怎么办?实际上,“别名”这种东西,也就是 alias
,几乎所有的脚本语言,都没有所谓的“永久别名”(Permanent alias),我们使用 Linux bash 、Cmder 之类的脚本工具,打开终端时,系统会默认执行一个脚本文件( bash 是用户目录下的 .bashrc
,Cmder 是 config/user_aliases.cmd
),而这样的脚本文件里,就包含了别名的定义。这也是为什么,我们在 Linux 类系统中,修改 .bashrc
后,必须要重新登出登录、或者 source .bashrc
的原因了。
所以,我们只要修改 Windows Powershell 启动时执行的文件就行了。很多论坛里面说,默认执行的脚本是 $Home\Documents\profile.ps1
,也就是 C:\Users\你的用户名\Documents\profile.ps1
,但是这并不正确,最好的方式是,先启动 PowerShell ,再执行 echo $profile
,这样得到的文件路径,才是 PowerShell 的默认执行文件路径。
然后,创建这个文件就好啦。
在文件里面,写上别名设置的语句。再一次注意,假如你的别名指代的命令含有空格,就不可以使用 New-Alias
命令,因为它不能带空格,即使你把指代的命令用引号括起来也没用。那怎么办呢?继续谷歌,原来,正确姿势是用 function
,也就是,我们把自己要定义的指令,定义为一个函数,就行啦。
保存文件,重新启动 PowerShell 以后,不出意外,应该会报一个 File xxxxxxx\Microsoft.PowerShell_profile.ps1 cannot be loaded because running scripts is disabled on this system.
根据此链接,出现这种情况,是因为 Windows 系统为了防止恶意脚本自动执行,故默认不允许自动运行脚本。所以,在确定自己有能力把控的情况下,__以管理员身份__,在 PowerShell 中执行 Set-ExecutionPolicy RemoteSigned
,即可。
再次重启 PowerShell,应该可以发现,自定义别名已经生效了。
如果你想为自己的 Windows PowerShell 设置永久的命令别名 (Alias),可以遵循以下步骤:
打开 PowerShell ,运行 echo $profile
,会输出一个文件路径。创建这个文件。
打开刚创建的文件,按以下格式设置多条别名:
1 | function 别名 { 需要替代的命令,可以包含空格 } |
以管理员身份打开 PowerShell,执行 Set-ExecutionPolicy RemoteSigned
。
重新启动 PowerShell ,应该已经完成了。