K162

Starwalker, Stardust.

0%

在使用 Laravel Artisan 生成 Seeder 的过程中,不小心输错了 Seeder 名

1
php artisan make:seeder FooTableSeeder

以至于填充数据时发生报错:

1
php artisan db:seed --class=BarTableSeeder

Illuminat\Contracts\Container\BindingResolutionException : Target class [BarTableSeeder] does not exist.

此时,如果单单修改生成的 Seeder 文件名 FooTableSeeder.phpBarTableSeeder,依然报错。

这是因为 Composer 的 autoloader 中仍存有错误的 classmap 记录,例如在 vendor/compser/autoload_classmap.php 中,我们可以看到原先错误的 classmap 记录:

1
'FooTableSeeder' => $baseDir . '/database/seeds/FooTableSeeder.php',

使用 dump-autoload 重新生成 Composer 的 autoloader:

1
composer dump-autoload

之后就可以顺利地进行数据填充了。

0x00 问题起因

为了方便操作数据库,我部署了 phpMyAdmin。但在使用 root 用户登录的时候,却提示:

mysqli_real_connect(): (hy000/1698): access denied for user ‘root’@’localhost’

0x01 解决方案

在检索了相关文章和资料后,了解到 MySQL 5.7+ 的版本,由于在安全机制上有一定的改动,因此默认情况下,命令行需要使用 sudo 来登录 root 用户。

StackExchange 上,用户 Rael Gugelmin Cunha 提供了一种解决方案,思路是:创建一个赋予了足够权限的新用户。1

具体步骤如下:

1、创建用户,并使用密码认证:

1
CREATE USER 'new_user'@'localhost' IDENTIFIED BY 'your_password';

2、赋予权限

1
GRANT ALL PRIVILEGES ON *.* TO 'new_user'@'localhost' WITH GRANT OPTION;

但是我觉得 WITH GRANT OPTION 可有可无。

3、刷新权限

1
FLUSH PRIVILEGES;

0x02 新的问题

创建用户后,我成功地使用新用户,通过 phpMyAdmin 登录了数据库。然而,同时我却发现,root 用户也能登录了。

为什么创建了新用户后,root 用户也能登录了?

0x03 MySQL 安全组件和插件

我开始摸索,MySQL 5.7+ 版本的 root 用户的安全机制上,到底在哪里出现了变动。

1. Socket Peer-Credential Authentication

同样是在 StackExchange 上,用户 Todor 提到:

If you install 5.7 and don’t provide a password to the root user, it will use the auth_socket plugin. That plugin doesn’t care and doesn’t need a password. It just checks if the user is connecting using a UNIX socket and then compares the username.2

在没有给 root 用户设置新密码前,root 用户默认使用 auth_socket 安全插件3auth_socket 通过检查当前用户是否使用 UNIX socket 并比较用户名来进行认证。

user 表中,就记录有相关的信息:

1
2
3
4
5
6
MariaDB [(none)]> select user,host,plugin from mysql.user;
+------+-----------+-------------+
| user | host | plugin |
+------+-----------+-------------+
| root | localhost | unix_socket |
+------+-----------+-------------+

换言之,对于我当前的 root 用户登录数据库,如果使用 unix_socket 安全插件,那就只需要:

1
sudo mysql

2. Native Authentication

在此之前,我都是使用 mysql_native_password 这种较为传统的方式。

而且平时,我习惯在 MySQL 环境中使用 SET PASSWORD 命令修改密码:

1
SET PASSWORD for root@localhost = password('new_password')

在执行完命令后,用户相应的 plugin 就会变成 mysql_native_password,并在 FLUSH PRIVILEGES 后生效。

0x04 为什么之前没有发现

想来想去,应该就是自己当时在**修改了 root 密码之后,没有及时 FLUSH PRIVILEGES**,且平时一直在用 sudo mysql -u root -p 登录数据库,所以没有意识到这些问题。

0x05 另外的解决方案

所以,除了创建新用户之外,把用户的安全认证方式从 UNIX_socket 修改成 mysql_native_password 也是一种办法。

因此可以通过一行命令来实现:

1
ALTER USER 'root'@'localhost' IDENTIFIED BY 'your_password';

当然,这种情况下,也可以设置一个空密码。如果修改 root 用户时,提示权限不足,可检查下是否是 sudo mysql 登录的。

参考链接

[1] askubuntu, Cannot enter phpmyadmin as root (MySQL 5.7)
[2] askubuntu, can’t login as mysql user root from normal user account in ubuntu 16.04
[3] Oracle, MySQL 8.0 Reference Manual

npm install 的过程中,突然报错:

1
Killed         ....] / extract:webpack-dev-middleware: sill doParallel extract 1609

针对这个问题,StackOverflow 用户 enRaiser 指出,可能是 Swap 空间不足引起1

查看当前 Swap 信息

使用 swapon -s 命令可以查看当前系统中的 swap 情况。如果返回为空,那么就是不存在 swap 文件。

也可以使用 free -h 查看当前系统中的 swap 使用情况:

1
2
3
4
[root@host]# free -h
total used free shared buff/cache available
Mem: 991M 216M 647M 620K 126M 633M
Swap: 0B 0B 0B

创建 Swap

使用 fallocate 可以很方便地预分配一片空间,创建 swap 文件。例如在根目录(也就是 / 目录)创建一个 2G 大小,且文件名为 swapfile 的 swap 文件:

1
fallocate -l 2G /swapfile

使用 ls -lh /swapfile 查看刚创建的 swap 文件:

1
-rw-r--r-- 1 root root 2.0G Jul 21 16:24 /swapfile

生效 Swap

虽然 swap 文件已经成功创建,但是发现,其权限是 -rw-r--r--,也就意味着非 root 权限的用户也能读取,因此记得改一下权限:

1
chmod 600 /swapfile

现在,使用 mkswap 就可以让 swapfile 作为系统的 swap 空间来使用:

1
mkswap /swapfile

然后使用 swapon 命令来激活刚刚的 swapfile

1
swapon /swapfile

验证 Swap

使用 swapon -s 来验证刚刚创建的 swap 文件:

1
2
3
[root@host]# swapon -s
Filename Type Size Used Priority
/swapfile file 2097148 0 -2

或者通过 free -h 来查看:

1
2
3
4
[root@host]# free -h
total used free shared buff/cache available
Mem: 991M 218M 598M 620K 174M 620M
Swap: 2.0G 0B 2.0G

包括在 htop 等应用中,也可以查看到刚创建的 swap 空间。

让 Swap 文件永久生效

刚刚创建的 swap 文件只在当前有效。系统重启之后,swapfile 不会自动生效。

因此,如果想让 swap 文件永久有效,那就需要修改 /etc 下的 fstab 文件,在最后一行加上:

1
/swapfile	swap	swap	sw	0	0

系统会在每次启动后检查这个文件,让 swapfile 生效,当作 swap 空间来使用。

OK,继续 npm install

参考链接

[1] StackOverflow, npm install always stuck at that extract:time-grunt

[2] DigitalOcean, How To Add Swap on CentOS 7

在使用 pip3 install --upgrade pip 升级 pip3 之后,运行 pip3 发生如下报错:

1
2
3
4
5
@raspberrypi:~ $ pip3
Traceback (most recent call last):
File "/usr/bin/pip3", line 9, in <module>
from pip import main
ImportError: cannot import name 'main' from 'pip' (/home/pi/.local/lib/python3.7/site-packages/pip/__init__.py)

报错的原因是 pip 升级后,main 函数发生了修改。因此根据报错提示,修改 /usr/bin/pip3 这个文件:

1
2
3
from pip import main    # 这是原先的语句
if __name__ == '__main__':
sys.exit(main())

修改为:

1
2
3
from pip._internal import main  # 修改后的语句
if __name__ == '__main__':
sys.exit(main())

如果在用 vim 修改文件的过程中,提示 readonly,可尝试使用 sudo 权限进行修改。

参考链接

[1] Stack Overflow. ImportError: cannot import name main when running pip –version command in windows7 32 bit

起因和症状

我将 ESP8266 与 Arduino UNO 的软串口连接,搭配 AT 指令进行使用。但由于 Arduino 的软串口无法到达 115200 波特率的传输速度,于是我参考乐鑫的文档1,根据其对 UART 配置描述提供的指令样例,给 ESP8266 发送了如下指令:

1
AT+UART_DEF=4800,8,1,0,3

紧接着,在 ESP8266 回复了一句 OK 后——ESP8266,完全沉默了。

在任何波特率,都无法获得 ESP8266 的响应。除了在 74880 波特率下能获得上电的系统日志信息。

问题梳理

在浏览了 Arduino 社区中遇到同样问题的相关讨论2,以及 StackOverflow3 中的相关问答后,我意识到,问题可能出在指令中最后一个参数上。

我重新翻阅了乐鑫的文档。文档中对 AT+UART_DEF 是这样描述的:

1
AT+UART_DEF=<baudrate>,<databits>,<stopbits>,<parity>,<flow control>

其中,<flow control> 为流控设置参数:

0:不使能流控
1:使能 RTS
2:使能 CTS
3:同时使能 RTS 和 CTS

文档关于这点也给出了相应的注意提示:

使用流控需要硬件支持流控:
MTCK 为 UART0 CTS;
MTDO 为 UART0 RTS

我使用的 ESP8266 是由安信可(Ai-Thinker)生产的 ESP-01S 模块。模块仅有的 8 个引脚中,没有 RTS 和 CTS 引脚。也就是说,在我设置了使能 RTS 和 CTS 进行流控后,在硬件上我却无法使用 RTS 和 CTS,所以 ESP8266 也就没有了响应

解决方案

刷机 刷固件。

总结

ESP8266 不使能 CTS 和 RTS 流控,设置波特率可使用:

1
AT+UART_DEF=9600,8,1,0,0

也可以使用:

1
AT+CIOBAUD=9600

参考链接

[1] Espressif. ESP8266 Non-OS SDK AT 指令集
[2] Arduino Forum. I changed ESP8266 Baud rate to 9600 - Now No communication !!!
[3] StackOverflow. Set baud rate to esp8266 at 9600

新浪财经行情的相关 API 可以通过浏览器开发者工具来挖掘、提取。整理如下。

沪深股市

HTTP 请求方式:GET

1
http://hq.sinajs.cn/list=<PRE><SYMBOL>

请求参数说明

PRE 可选前缀 说明
sh 上交所股票(基金)前缀
s_sh 上交所股票(基金)前缀,省略五档报价等信息
sz 深交所股票(基金)前缀
s_sz 深交所股票(基金)前缀,省略五档报价等信息

SYMBOL 为股票代码。如:000001,为上证指数。

返回说明

麦子店高盛 中信证券(600030),且获取五档报价信息为例:

1
http://hq.sinajs.cn/list=sh600030

返回数据如下:

1
var hq_str_sh600030="中信证券,20.080,20.080,21.090,21.160,20.040,21.090,21.100,221743961,4597038936.000,851863,21.090,322800,21.080,435235,21.070,342211,21.060,289618,21.050,777017,21.100,325000,21.110,255800,21.120,241600,21.130,248400,21.140,2019-06-11,15:00:00,00";

各个返回的参数说明如下:

序号 示例 说明
0 中信证券 股票(指数)名称
1 20.080 今日开盘
2 20.080 昨日收盘
3 21.090 最新价格
4 21.160 今日最高
5 20.040 今日最低
6 21.090 竞买价,即“买一”报价
7 21.100 竞卖价,即“卖一”报价
8 221743961 成交量
9 4597038936.000 成交额
10 851863 “买一”报价股数,即约 8519 手
11 21.090 “买一”报价
12-19 …… “买二”至“买五”报价
20-29 …… “卖一”至“卖五”报价
30 2019-06-11 日期
31 15:00:00 时间
32 00 好像收盘后会出现这个标签

虽然里面没有涨跌幅数据,但是可以通过当前价格与昨日收盘计算得到。

多个查询

上述接口也可一次性请求多个股票代码:

1
http://hq.sinajs.cn/list=sh000001,sz399001

返回数据如下:

1
2
var hq_str_sh000001="上证指数,2854.0704,2852.1302,2905.4450,2907.5344,2854.0704,0,0,145152763,141817520795,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2019-06-11,11:35:03,00";
var hq_str_sz399001="深证成指,8721.272,8711.786,8964.885,8970.501,8718.472,0.000,0.000,18135395376,177191151062.308,0,0.000,0,0.000,0,0.000,0,0.000,0,0.000,0,0.000,0,0.000,0,0.000,0,0.000,0,0.000,2019-06-11,11:35:03,00";

港股

HTTP 请求方式:GET

1
http://hq.sinajs.cn/list=hk<SYMBOL>

SYMBOL 为股票代码。如 HSI 为恒生指数,00728 为中国电信:

1
http://hq.sinajs.cn/list=hkHSI,hk00728

美股

HTTP 请求方式:GET

1
http://hq.sinajs.cn/list=gb_<SYMBOL>

请求参数说明

SYMBOL 为股票代码。如:ixic 为纳斯达克综合指数,dji,为道琼斯工业指数。

返回说明

BILI 哔哩哔哩为例,请求 URL 如下:

1
http://hq.sinajs.cn/list=gb_bili

正常情况下,服务器会返回以下信息:

1
var hq_str_gb_bili="哔哩哔哩,15.0600,1.76,2019-06-11 09:31:51,0.2600,14.9100,15.3100,14.8800,22.7000,9.0900,3584557,3849047,4698720000,-0.34,--,0.00,0.00,0.00,0.00,312000000,0.00,15.1100,0.33,0.05,Jun 10 08:00PM EDT,Jun 10 04:00PM EDT,14.8000,20455.00";

返回的主要参数说明如下:

序号 参数 说明
0 哔哩哔哩 股票名称
1 15.0600 最新价格
2 1.176 涨跌幅
3 2019-06-11 09:31:51 日期与时间
4 0.2600 涨跌额
5 14.9100 今日开盘
6 15.3100 今日最高
7 14.8800 今日最低
8 22.7000 52周最高
9 9.0900 52周最低
10 3584557 成交量
11-27 …… ……

市场指数

市场指数的数据,一般会有至少 15 分钟的延迟。请留意返回的行情时间!

英国富时100,德国 DAX,法国 CAC40 这些指数可以通过如下方式请求:

HTTP 请求方式:GET

1
http://hq.sinajs.cn/list=b_<SYMBOL>

<SYMBOL> 为指数代码,如德国 DAX 指数:

1
http://hq.sinajs.cn/list=b_DAX

外汇

指数

HTTP 请求方式:GET

1
http://hq.sinajs.cn/list=<SYMBOL>

<SYMBOL> 为指数代码,如 DINIW 美元指数:

1
http://hq.sinajs.cn/list=DINIW

汇率

HTTP 请求方式:GET

1
http://hq.sinajs.cn/list=<CA><CB>

CA 为持有货币,CB 为兑换货币,如 USDCNY 在岸人民币:

1
http://hq.sinajs.cn/list=CNYUSD

还可通过如下 URL 获取各个银行的外汇牌价:

1
http://vip.stock.finance.sina.com.cn/forex/api/openapi.php/ForexService.getBankForex?callback=getAllBankForex

BBR(Bottleneck Bandwidth and RTT)是一个 Google 发布的拥塞控制算法。

上世纪 80 年代以来,我们的互联网大多采用 Reno 或 CUBIC 这样基于丢包的拥塞控制策略。它们根据数据的丢包情况,来决定是否应该降低速度。虽然这么多年来,它们都表现得不错,但对于今天的互联网而言,就显得有些过时了。

BBR 则通过持续地探测当前网络的最大带宽和 RTT,建立一个当前网络的显式模型,并借助这个模型,控制当前网络的出站数据。同时,能减少 buffer 在链路中的占用率。

当 Google 在其内部的骨干网,Google.com 和 Youtube 部署了 BBR 后,发现 BBR 能显著地提高网络的吞吐量,并降低延迟。

开启 BBR 要求 4.10 以上版本的内核。如果嫌麻烦,就用 @teddysun 大佬的一键脚本吧:

1
wget --no-check-certificate https://github.com/teddysun/across/raw/master/bbr.sh && chmod +x bbr.sh && ./bbr.sh

Obtain Kernel with BBR

可先用如下命令查看当前内核版本:

1
uname -r

如果内核版本低于 4.10,可使用 ELRepo 的源进行更新:

1
2
3
sudo rpm --import https://www.elrepo.org/RPM-GPG-KEY-elrepo.org
sudo rpm -Uvh http://www.elrepo.org/elrepo-release-7.0-2.el7.elrepo.noarch.rpm
sudo yum --enablerepo=elrepo-kernel install kernel-ml -y

安装完成后,查看已安装的内核:

1
rpm -qa | grep kernel

输出结果大致如下:

1
2
3
4
5
[root@host ~]# rpm -qa | grep kernel
kernel-ml-4.10.4-1.el7.elrepo.x86_64
kernel-3.10.0-514.el7.x86_64
kernel-tools-3.10.0-514.el7.x86_64
kernel-tools-libs-3.10.0-514.el7.x86_64

如果有看到类似 kernel-ml-4.10.4-1.el7.elrepo.x86_64 版本大于 4.10 的内核,说明安装成功。

Configure GRUB

运行如下命令来查看 GRUB 的启动项:

1
sudo egrep ^menuentry /etc/grub2.cfg | cut -f 2 -d \'

输出结果大致如下:

1
2
3
4
[root@host ~]# sudo egrep ^menuentry /etc/grub2.cfg | cut -f 2 -d \'
CentOS Linux (4.10.4-1.el7.elrepo.x86_64) 7 (Core)
CentOS Linux (3.10.0-514.el7.x86_64) 7 (Core)
CentOS Linux (0-rescue-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb) 7 (Core)

输出的项目从 0 开始编号。以上面的结果为例,4.10 的内核版本位于第一个,那么就设置默认启动项为 0:

1
sudo grub2-set-default 0

然后 reboot 重启系统!重启后,再次执行 uname -r 检查内核版本是否顺利升级。

BBR, Get Daze~!

执行如下命令来启用 BBR:

1
2
3
echo 'net.core.default_qdisc=fq' | sudo tee -a /etc/sysctl.conf
echo 'net.ipv4.tcp_congestion_control=bbr' | sudo tee -a /etc/sysctl.conf
sudo sysctl -p

可用如下命令检查当前可用的 TCP 拥塞控制算法:

1
2
[root@host ~]# sudo sysctl net.ipv4.tcp_available_congestion_control
net.ipv4.tcp_available_congestion_control = bbr cubic reno

执行如下命令检查 BBR 是否启动:

1
2
3
4
[root@host ~]# sudo sysctl -n net.ipv4.tcp_congestion_control
bbr
[root@host ~]# lsmod | grep bbr
tcp_bbr 16384 8

如果返回的模块中有 tcp_bbr,那么就顺利启用了 BBR!

参考链接

[1] Linux TCP BBR commit
[2] CentOS7 开启Google BBR加速 让你的VPS更快

Windows 环境下,在 powershell 中执行 vagrant up 后,虚拟机启动发生异常,久久没有响应。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
PS C:\Andromeda\Homestead> vagrant up
Bringing machine 'homestead-7' up with 'virtualbox' provider...
==> homestead-7: Checking if box 'andromeda/homestead' is up to date...
==> homestead-7: Clearing any previously set forwarded ports...
==> homestead-7: Clearing any previously set network interfaces...
==> homestead-7: Preparing network interfaces based on configuration...
homestead-7: Adapter 1: nat
homestead-7: Adapter 2: hostonly
==> homestead-7: Forwarding ports...
homestead-7: 80 (guest) => 8000 (host) (adapter 1)
homestead-7: 443 (guest) => 44300 (host) (adapter 1)
homestead-7: 3306 (guest) => 33060 (host) (adapter 1)
homestead-7: 4040 (guest) => 4040 (host) (adapter 1)
homestead-7: 5432 (guest) => 54320 (host) (adapter 1)
homestead-7: 8025 (guest) => 8025 (host) (adapter 1)
homestead-7: 27017 (guest) => 27017 (host) (adapter 1)
homestead-7: 22 (guest) => 2333 (host) (adapter 1)
==> homestead-7: Running 'pre-boot' VM customizations...
==> homestead-7: Booting VM...
==> homestead-7: Waiting for machine to boot. This may take a few minutes...
homestead-7: SSH address: 127.0.0.1:2333
homestead-7: SSH username: vagrant
homestead-7: SSH auth method: private key
...

等待数分钟之后,提示 Timed out:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
Timed out while waiting for the machine to boot. This means that
Vagrant was unable to communicate with the guest machine within
the configured ("config.vm.boot_timeout" value) time period.

If you look above, you should be able to see the error(s) that
Vagrant had when attempting to connect to the machine. These errors
are usually good hints as to what may be wrong.

If you're using a custom box, make sure that networking is properly
working and you're able to connect to the machine. It is a common
problem that networking isn't setup properly in these boxes.
Verify that authentication configurations are also setup properly,
as well.

If the box appears to be booting properly, you may want to increase
the timeout ("config.vm.boot_timeout") value.

参考 StackOverflow 上的讨论1,BrianC 给出方案说,可尝试开启 GUI 模式,以此来更好地追踪错误。具体做法就是在 Vagrantfile 中取消下面这段配置的注释:

1
2
3
config.vm.provider "virtualbox" do |vb|
vb.gui = true
end

如果文件中原先就没有的话,可直接在 Vagrantfile 写入这段配置,然后重新尝试 vagrant up,得到提示:

VT-x/AMD-V 硬件加速在您的系统中不可用。您的 64-位虚拟机将无法检测到 64-位处理器,从而无法启动。

看来,可能是主板的 BIOS 设置中,没有开启虚拟化支持。

参考链接

[1] Vagrant up timeout - StackOverflow

在 Laravel 经历 5.1 到 5.5 版本升级的过程中,追加了对于 emoji 字符的支持。因此,其默认的数据库字符集也换成了 utf8mb4。但是,如果服务器的 MySQL 数据库版本低于 5.7.7(或 Mariadb 低于 10.2.2),就会遇到以下的错误:

1
2
3
4
5
6
7
8
9
10
11
12
13
[root@summer Andromeda]# php artisan migrate
Migration table created successfully.

In Connection.php line 664:

SQLSTATE[42000]: Syntax error or access violation: 1071 Specified key was too long; max key length is 767 bytes (SQL: alter table `users` add unique `user
s_email_unique`(`email`))


In Connection.php line 458:

SQLSTATE[42000]: Syntax error or access violation: 1071 Specified key was too long; max key length is 767 bytes

根据 Laravel 文档1 中的描述:

you may need to manually configure the default string length generated by migrations in order for MySQL to create indexes for them. You may configure this by calling the Schema::defaultStringLength method within your AppServiceProvider

也就是说,要在 AppServiceProviderboot() 中,通过调用 Schema::defaultStringLength(),来修改默认字符串长度,例如这样:

1
2
3
4
5
6
7
8
9
10
11
use Illuminate\Support\Facades\Schema;

/**
* Bootstrap any application services.
*
* @return void
*/
public function boot()
{
Schema::defaultStringLength(191);
}

除此之外,文档中也提到,还可以修改数据库的 innodb_large_prefix 选项来避免报错。

参考链接

[1] Laravel Documentation - migrations
[2] Eric L. Barnes, Laravel 5.4: Specified key was too long error

最近购买了一块 Arduino UNO 开发板,今天到手后便立马开始尝鲜。但很快就遇到了问题。在 Windows 下,使用 Arduino IDE 编写好代码并准备上传至 Arduino 中时,IDE 报错并提示说:

1
2
3
4
5
6
上传项目出错
开发版在 COM1 不可用
Using Port : COM1
Using Programmer : arduino
Overriding Baud Rate : 115200
avrdude: ser_open(): can't open device "\\.\COM1": 系统找不到指定文件

在经过 面向 Stack Overflow 编程 搜索 Stack Overflow 的问答之后,发现是 USB 转串行通讯接口后的 COM 端口号不一致引起的。1

随后,我找到了两种解决方案。

第一种办法是打开 Windows 的设备管理器,找到 端口(COM 和 LPT),选择 Arduino 相对应的 USB 串行设备,如 “USB 串行设备(COM2)”。打开其属性面板,切换至 端口设置 的标签页,有一个 高级(A)... 按钮,点击后出现高级设置页面,将底部的 COM 端口号(P) 设置为 COM1 即可。设置完毕后,需要断开 Arduino 的 USB 线缆,并重新连接。

第二种办法则是在 Arduino IDE 中,选择顶部标签栏中的 工具,找到端口的设置选项。选择已连接的相应 COM 端口号即可。然后可直接编译并上传 IDE 中的程序。

虽然仍未在 macOS 中尝试 Arduino IDE,但我猜测,在 macOS 中遇到类似问题时,第二种办法或许是较为有效便捷的解决途径。

参考链接

[1] user65439, Answer for arduino nano-avrdude: ser_open(): system…