WireGuard 教程:WireGuard 的工作原理

本文翻译自:https://github.com/pirate/wireguard-docs

WireGuard 是由 Jason Donenfeld 等人用 C 语言编写的一个开源 VPN 协议,被视为下一代 VPN 协议,旨在解决许多困扰 IPSec/IKEv2OpenVPN 或 L2TP 等其他 VPN 协议的问题。它与 Tinc 和 MeshBird 等现代 VPN 产品有一些相似之处,即加密技术先进、配置简单。从 2020 年 1 月开始,它已经并入了 Linux 内核的 5.6 版本,这意味着大多数 Linux 发行版的用户将拥有一个开箱即用的 WireGuard。

无论你是想破墙而出,还是想在服务器之间组网,WireGuard 都不会让你失望,它就是组网的『乐高积木』,就像 ZFS 是构建文件系统的『乐高积木』一样。

继续阅读WireGuard 教程:WireGuard 的工作原理

满血复活 手把手教你更换iPad 2电池

查阅了一些拆解教程,发现难度不小。虽然有拆解平板的经验,但实际拆解这部iPad 2遇到的困难超过心理预期。

难度主要集中在三个方面:

1、虽然iPad 2代表了当年最高的工艺、工业设计。但彼时的屏幕,触控屏和显示屏并不是一个总成。也就是「外屏」、「内屏」是分体的。且外屏的排线压在内屏下面。

2、彼时「易拉胶」还没有广泛应用到数码产品上,iPad 2内部都是双面胶。

3、无尘环境。

结合步骤,下文详述。

继续阅读满血复活 手把手教你更换iPad 2电池

Flutter 状态管理框架 Provider 和 Get 分析

状态管理一直是 Flutter 开发中一个火热的话题。谈到状态管理框架,社区也有诸如有以 GetProviderRiverpod 为代表的多种方案,它们有各自的优缺点。面对这么多的选择,你可能会想:「我需要使用状态管理么?哪种框架更适合我?」本文将从作者的实际开发经验出发,分析状态管理解决的问题以及思路,希望能帮助你做出选择。

为什么需要状态管理?

首先,为什么需要状态管理?根据笔者的经验,这是因为 Flutter 基于 声明式 构建 UI ,使用状态管理的目的之一就是解决「声明式」开发带来的问题。

「声明式」开发是一种区别于传原生的方式,所以我们没有在原生开发中听到过状态管理,那如何理解「声明式」开发呢?

继续阅读Flutter 状态管理框架 Provider 和 Get 分析

Flutter Riverpod 全面深入解析,为什么官方推荐它?

随着 Flutter 的发展,这些年 Flutter 上的状态管理框架如“雨后春笋”般层出不穷,而近一年以来最受官方推荐的状态管理框架无疑就是 Riverpod ,甚至已经超过了 Provider ,事实上 Riverpod 官方也称自己为 “Provider,但与众不同”。

Provider 本身用它自己的话来说是 “InheritedWidget 的封装,但更简单且复用能力更强。” ,而 Riverpod 就是在 Provider 的基础上重构了新的可能。

关于过去一年状态管理框架的对比可以看 《2021 年的 Flutter 状态管理:如何选择?》本文主要是带你解剖 RiverPod 的内部是如何实现,理解它的工作原理,以及如何做到比 Provider 更少的模板和不依赖 BuildContext

继续阅读Flutter Riverpod 全面深入解析,为什么官方推荐它?

macOS Sonoma(14.2.1)通过Docker编译Android 12.1源码过程总结(MacBook Pro 2023-Apple M2 Pro)

前置条件


根据 Google 官方文档,2021年6月22日之后的Android系统版本不支持在macOS系统上构建,我们在 Applic SiliconmacOS 系统是不能直接成功构建后续版本的,但是之前的版本可以在修改编译配置后成功编译,只是是否能正常运行存疑

另外,我们需要安装 Rosetta 2 支持运行部分 x86_64 应用。注意  Rosetta 2 只支持 64 位应用,不支持 32 位应用。 参考 Does Rosetta 2 support 32-bit Intel apps?

继续阅读macOS Sonoma(14.2.1)通过Docker编译Android 12.1源码过程总结(MacBook Pro 2023-Apple M2 Pro)

M1 CPU 那么多的核,macOS 是怎样管理的?

1984 年 1 月,Apple 开始设计、开发和销售个人电脑系列产品 Macintosh。在这近 40 年时间里,Apple 浓墨重彩地书写了许多科技史上的里程碑,其中就包括了三个非常重要的时间点——1994 年从摩托罗拉 68000 架构迁移至 PowerPC 平台、 2005 年从 PowerPC 平台迁移至英特尔 x86 平台、2020 年从英特尔 x86 平台迁移至 Apple Silicon。

2020 年 11 月 11 日 Apple 在加州 Cupertino 正式发布了 M1 芯片,不仅是 Apple 自己首款基于 ARM 架构的用于个人电脑的自研处理器,而且其强大的性能也让当时苦「牙膏厂」久已的 Geeker 们也感到异常亢奋。

不过,看得见的风光总是与看不到的努力分不开的。作为专为 Mac 设计、优化的芯片,系统到底是怎么将程序调度在 M 系列处理器上的。

继续阅读M1 CPU 那么多的核,macOS 是怎样管理的?

Box64 running on M1 with Asahi

The Asahi project has now released a first alpha version, so I tried that on a MacBookPro. Asahi is a full linux distribution that can be installed on mac with an M1 processor, it installs alongside your current macOS. It’s an alpha release so many things are missing for now, including 3D hardware acceleration, but on the other hand, for an alpha release, many things are already working, and working fine!

After a (quite) long installation process, I got linux running on that mac. Note that I add to restart the installation process, as the mac went to sleep mode during “root expension” and that actually froze the installation. I needed to break, remove all the create partitions (a risky process) to be able to start again.

Now, the M1 processor is very fast ARM64 processor, but it only supports 64bits operations. No ARM32 there, so no box86. Also, the Asahi readme mentions that the Pagesize is 16K, instead of the standard 4K. That breaks a few things on the way. Fortunatly, I had already encountered a system with 16K pagesize (Loongarch64 systems), so there is some supporting code on box64 already for it. And after enabling it (plus some compilation options), box64, with dynarec, was running!

To try things, I wanted to install a simple linux game. Remember that there is no Hardware acceleration yet, so I choose WorldOfGoo, with its simple graphics (it’s still an OpenGL game). Launching the install didn’t work, as by default, the setup tries to run x86 code (32bits, so needing box86 not available here). To work around that, I created a simple uname script that spoofs the setup into thinking this is an x86_64 system:

the file simply contains

#!/bin/bash

if [ "$1" == "-m" ];then
 echo x86_64
 exit 0
fi

/bin/uname "$@"

And I created an x86_64 folder in my home directory to put some pc stuffs (and that uname script)

Then I launched the setup as PATH=~/x86_64:$PATH ./WorldOfGoo.Linux.153.sh et voilà, the setup launched… But as text only… Ok, gtk2 libs are not installed. So sudo pacman -S gtk2 and try again…

继续阅读Box64 running on M1 with Asahi

Musl libc:为什么我们会需要另一个 libc?

如果你是一个 Linux 用户,那你一定至少听说过 Glibc 的鼎鼎大名,或者甚至在日常使用中碰到不少关于它的问题,例如 Glibc 版本不匹配等问题。而本文的主角—— Musl libc 与之相比就要默默无闻的多,毕竟绝大多数的 Linux 发行版使用的 libc 库都是 Glibc,只有 Alpine Linux 等极少数 Linux 发行版才会使用 Musl libc,并且还会遇到诸如闭源 JDK 无法正常使用等问题的困扰,那么,为什么我们会需要另一个 libc 函数库呢?

Glibc 并不完美

Glibc 作为目前使用最广泛的 libc 函数库,虽然拥有最广泛的发行版支持和用户群体,并且在兼容性和性能方面也存在一些优势,但它并不完美,有三个问题严重困扰着它。

代码库陈旧

Glibc 拥有悠久的历史——对于软件而言这可能并不一定是一句赞誉,尤其是当你需要处理上世纪九十年代就存在的代码库时。三十多年来,程序员们编写 C 程序的方式并不是一成不变的,某些在那个年代被认为是好习惯或者是必须的编程方式在今天看来可能完全不合时宜,诸如叠床架屋的宏等等。这些问题严重拖累了 Glibc 的源码可读性,例如下面这一段源代码,摘自 Glibc 的 fopen 函数。

FILE *
__fopen_internal (const char *filename, const char *mode, int is32)
{
  struct locked_FILE
  {
    struct _IO_FILE_plus fp;
#ifdef _IO_MTSAFE_IO
    _IO_lock_t lock;
#endif
    struct _IO_wide_data wd;
  } *new_f = (struct locked_FILE *) malloc (sizeof (struct locked_FILE));

  if (new_f == NULL)
    return NULL;
#ifdef _IO_MTSAFE_IO
  new_f->fp.file._lock = &new_f->lock;
#endif
  _IO_no_init (&new_f->fp.file, 0, 0, &new_f->wd, &_IO_wfile_jumps);
  _IO_JUMPS (&new_f->fp) = &_IO_file_jumps;
  _IO_new_file_init_internal (&new_f->fp);
  if (_IO_file_fopen ((FILE *) new_f, filename, mode, is32) != NULL)
    return __fopen_maybe_mmap (&new_f->fp.file);

  _IO_un_link (&new_f->fp);
  free (new_f);
  return NULL;
}

作为对比,下面是 Musl 库中同样对 fopen 函数的实现

FILE *fopen(const char *restrict filename, const char *restrict mode)
{
    FILE *f;
    int fd;
    int flags;

    /* Check for valid initial mode character */
    if (!strchr("rwa", *mode)) {
        errno = EINVAL;
        return 0;
    }

    /* Compute the flags to pass to open() */
    flags = __fmodeflags(mode);

    fd = sys_open(filename, flags, 0666);
    if (fd < 0) return 0;
    if (flags & O_CLOEXEC)
        __syscall(SYS_fcntl, fd, F_SETFD, FD_CLOEXEC);

    f = __fdopen(fd, mode);
    if (f) return f;

    __syscall(SYS_close, fd);
    return 0;
}

两者的可读性差距不言自明,笔者在这里并非是要批判 Glibc 的代码风格,但对于初次上手阅读源码的人来说,显然是 Musl 的风格更加友好,更便于理解。

体积过大

由于 Glibc 相较体积更加关注性能,因此其链接生成的二进制文件相较于 Musl uClibc 等专注于嵌入式等场合的库来说要大很多,而这些场合往往非常关注几百 K 大小的区别,因为 SRAM 的大小往往关乎整体开发板的成本。

下面这张表展示了不同 libc 库编译的文件大小。

尺寸对比 musl uClibc dietlibc glibc
.a 426k 500k 120k 2.0M
.so 527k 560k 185k 7.9M
静态最小 1.8k 5k 0.2k 662k
静态输出 13k 70k 6k 662k

可以看出 Glibc 在程序大小上明显大于其他 libc 库,此外,这里的静态也是有水分的,这就引出了 Glibc 的下一个问题,也是最重要的问题之一:静态链接。

对静态链接支持不佳

理论上来说,Glibc 是支持静态链接的。但,这也仅仅是从理论上来说,由于一些历史遗留问题(当然,也包括对功能实现的考虑)Glibc 的静态链接并不是真正的静态链接:如果你的程序中使用了某些不支持静态链接的特性(这一点在大型软件中非常常见),那么即便你在链接时选择静态链接,生成出来的程序实际上仍然是依赖于 Glibc 动态库的,一旦你尝试删除掉它,你立马就会发现这些“静态”链接的程序统统罢工不干了。

谁在用 Musl?

在发行版中,主要是 Alpine Linux,作为最特立独行的 Linux 发行版之一,它选用了 Musl + Busybox 的组合,而非通常的 Glibc + Coreutils,这使得它的最小安装可以控制在惊人的 5 MB 之内!相比之下,普通的 CentOS 最小安装则需要 200 MB 左右,这一点使得它在嵌入式等对内存占用极为敏感的场合占据了相当的优势。

此外,Musl 从设计之初就很关注静态链接的可用性,因此它完全可以被静态链接进其他程序中,不存在 Glibc 对动态库的依赖问题,这一点也有助于缓解不同版本 libc 之间的兼容性问题——只要我把万物都静态链接进去,就不存在版本问题了。当然,这种做法也会带来体积膨胀等问题,所以并不是一个太好的解决方案。

Musl 的问题与未来

虽然拥有诸多优点,但 Musl 在性能方面逊于 Glibc 也是不争的事实,毕竟简化实现的代价就包括牺牲性能,不过这一点并非不可拯救,通过使用开源的 malloc 实现(诸如微软的实现)替换这些对性能影响较大的热点函数,就可以在很大程度上解决性能方面的问题。

同时,试图取代或至少部分取代 Glibc 的库也并不止 Musl 一个, 例如用于 AOSP 项目上的 bionic,以及广泛应用于各种嵌入式开发中的 uClibc 等。与它们相比,Musl 背后既没有 Google 这样的大公司撑腰,在压缩体积方面做的也不够极致,相较之下就没有那么受到开发者们的青睐,在新功能和新特性跟进上也不是非常积极。

出于这些原因,也许 Musl 在今后的很长一段时间内会继续保持这种“小而美”的特点,但这对于我们来说并非就是一件坏事,能够看到与 GNU Glibc 风格截然不同的另一种实现,对于 Linux 社区的多样性,以及对于我们这些学习者来说,何尝不是一件美事?

参考链接