Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions src/zh-CN/02-01-sha-digest.smd
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
---
.title = "计算文件的 SHA-256 摘要",
.date = "2024-01-01",
.author = "ZigCC",
.layout = "section.shtml",
---
计算文件的 SHA-256 摘要

标准库中实现了许多加密算法,`sha256` 和 `md5` 都是开箱即用的。

[]($code.siteAsset('src/02-01.zig').language('zig'))
14 changes: 14 additions & 0 deletions src/zh-CN/02-02-pbkdf2.smd
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
---
.title = "使用 PBKDF2 对密码进行加盐和哈希",
.date = "2024-01-01",
.author = "ZigCC",
.layout = "section.shtml",
---
使用 PBKDF2 对密码进行加盐和哈希

使用 [`std.crypto.pwhash.pbkdf2`] 对加盐后的密码进行哈希处理。盐值是使用 [`std.rand.DefaultPrng`] 生成的,它用生成的随机数填充盐值字节数组。

[]($code.siteAsset('src/02-02.zig').language('zig'))

[`std.crypto.pwhash.pbkdf2`]: https://ziglang.org/documentation/0.11.0/std/#A;std:crypto.pwhash.pbkdf2
[`std.rand.defaultprng`]: https://ziglang.org/documentation/0.11.0/std/#A;std:rand.DefaultPrng
14 changes: 14 additions & 0 deletions src/zh-CN/02-03-argon2.smd
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
---
.title = "使用 Argon2 对密码进行加盐和哈希",
.date = "2025-08-28",
.author = "ZigCC",
.layout = "section.shtml",
---
使用 Argon2 对密码进行加盐和哈希

此 Zig 程序使用 Argon2id 密码哈希算法从密码和盐值派生加密密钥。它使用 [std.crypto.pwhash.argon2] 对加盐后的密码进行哈希处理,其中盐值是使用 [`std.crypto.random`] 生成的。

[]($code.siteAsset('src/02-03.zig').language('zig'))

[`std.crypto.pwhash.argon2`]: https://ziglang.org/documentation/0.14.0/std/#std.crypto.pwhash.argon2
[`std.crypto.random`]: https://ziglang.org/documentation/0.14.0/std/#std.crypto.tlcsprng.interface
18 changes: 18 additions & 0 deletions src/zh-CN/03-01-elapsed-time.smd
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
---
.title = "测量两个代码段之间的经过时间",
.date = "2024-01-01",
.author = "ZigCC",
.layout = "section.shtml",
---

[`Instant`] 表示相对于当前执行程序的时间戳,即使程序挂起它也会继续计时,可用于记录经过的时间。

调用 [`std.time.Instant.since`] 返回一个表示经过纳秒数的 u64。

这是一个非常常见的任务,为了方便起见,提供了一个 [`Timer`]。

[]($code.siteAsset('src/03-01.zig').language('zig'))

[`instant`]: https://ziglang.org/documentation/0.11.0/std/#A;std:time.Instant
[`timer`]: https://ziglang.org/documentation/0.11.0/std/#A;std:time.Timer
[`std.time.instant.since`]: https://ziglang.org/documentation/0.11.0/std/#A;std:time.Instant.since
22 changes: 22 additions & 0 deletions src/zh-CN/04-01-tcp-server.smd
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
---
.title = "监听未使用的 TCP/IP 端口",
.date = "2024-01-01",
.author = "ZigCC",
.layout = "section.shtml",
---

在此示例中,端口显示在控制台上,程序将监听直到收到请求。将端口设置为 0 时,`Ip4Address` 会分配一个随机端口。

[]($code.siteAsset('src/04-01.zig').language('zig'))

启动后,请尝试像这样进行测试:

```bash
echo "hello zig" | nc localhost <port>
```

默认情况下,程序使用 IPv4 进行监听。如果您想要 IPv6,请使用 `::1` 代替 `127.0.0.1`,将 `net.Ip4Address.parse` 替换为 `net.Ip6Address.parse`,并在创建 `net.Address` 时将字段 `.in` 替换为 `.in6`。

(并连接到像 `ip6-localhost` 之类的地址,具体取决于您的机器设置。)

下一节将演示如何使用 Zig 代码连接到此服务器。
13 changes: 13 additions & 0 deletions src/zh-CN/04-02-tcp-client.smd
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
---
.title = "TCP 客户端",
.date = "2024-01-01",
.author = "ZigCC",
.layout = "section.shtml",
---

在此示例中,我们要创建一个 TCP 客户端来连接上一节中的服务器。
您可以使用 `zig build run-04-02 -- <port>` 运行它。

[]($code.siteAsset('src/04-02.zig').language('zig'))

默认情况下,程序使用 IPv4 连接。如果您想要 IPv6,请使用 `::1` 代替 `127.0.0.1`,将 `net.Address.parseIp4` 替换为 `net.Address.parseIp6`。
18 changes: 18 additions & 0 deletions src/zh-CN/04-03-udp-echo.smd
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
---
.title = "UDP 回显",
.date = "2024-01-01",
.author = "ZigCC",
.layout = "section.shtml",
---

与 TCP 服务器示例类似,此程序将侦听指定的 IP 地址和端口,但这次是侦听 UDP 数据报。如果接收到数据,它将被回显到发送者的地址。

尽管 `std.net` 主要侧重于 TCP 的抽象(目前为止),我们仍然可以利用套接字编程通过 UDP 进行通信。

[]($code.siteAsset('src/04-03.zig').language('zig'))

启动程序后,使用 `nc` 进行如下测试,使用 `-u` 标志表示 UDP:

```bash
echo "hello zig" | nc -u localhost <port>
```
16 changes: 16 additions & 0 deletions src/zh-CN/05-01-http-get.smd
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
---
.title = "GET",
.date = "2024-01-01",
.author = "ZigCC",
.layout = "section.shtml",
---

解析提供的 URL 并使用 [`request`] 发出同步 HTTP GET 请求。打印获取到的 [`Response`] 状态和标头。

> 注意:由于 HTTP 支持尚处于早期阶段,对于任何复杂的任务,建议使用 [libcurl](https://curl.se/libcurl/c/)。
> 并且如果缓冲区不足,它将返回 `error.HttpHeadersOverSize`

[]($code.siteAsset('src/05-01.zig').language('zig'))

[`request`]: https://ziglang.org/documentation/0.11.0/std/src/std/http/Client.zig.html#L992
[`response`]: https://ziglang.org/documentation/0.11.0/std/src/std/http/Client.zig.html#L322
15 changes: 15 additions & 0 deletions src/zh-CN/05-02-http-post.smd
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
---
.title = "POST",
.date = "2024-01-01",
.author = "ZigCC",
.layout = "section.shtml",
---

解析提供的 URL 并使用 [`request`] 发出同步 HTTP POST 请求。打印获取到的 [`Response`] 状态以及从服务器接收的数据。

> 注意:由于 HTTP 支持尚处于早期阶段,对于任何复杂的任务,建议使用 [libcurl](https://curl.se/libcurl/c/)。

[]($code.siteAsset('src/05-02.zig').language('zig'))

[`request`]: https://ziglang.org/documentation/0.11.0/std/src/std/http/Client.zig.html#L992
[`response`]: https://ziglang.org/documentation/0.11.0/std/src/std/http/Client.zig.html#L322
52 changes: 52 additions & 0 deletions src/zh-CN/05-03-http-server-std.smd
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
---
.title = "http.Server - std",
.date = "2024-01-01",
.author = "ZigCC",
.layout = "section.shtml",
---

自 Zig 0.12.0 起引入了 `http.Server` 的基本实现。

对于每个连接,我们生成一个新线程来处理它,在 `accept` 中它将:
1. 首先,它使用 `defer` 确保返回时关闭连接。
2. 然后初始化 HTTP 服务器以开始解析请求
3. 对于每个请求,我们首先检查它是否可以升级到 WebSocket。
- 如果成功,则调用 `serveWebSocket`,否则调用 `serverHTTP`

[]($code.siteAsset('src/05-03.zig').language('zig'))

## 测试

对于 HTTP,我们可以使用 `curl`:
```bash
curl -v localhost:8080
```
它将输出:
```bash
< HTTP/1.1 200 OK
< content-length: 32
< custom header: custom value
<
Hello World from Zig HTTP server
```

对于 WebSocket,我们可以使用浏览器 `开发者工具` 中的控制台:

```js
var webSocket = new WebSocket('ws://localhost:8080');
webSocket.onmessage = function(data) { console.log(data); }
```
然后我们可以像这样发送消息:
```js
webSocket.send('abc')
```

[websocket-client]($image.siteAsset('images/websocket-client.webp'))

有关详细信息,请参阅 [Writing WebSocket client applications - Web APIs | MDN](https://developer.mozilla.org/en-US/docs/Web/API/WebSockets_API/Writing_WebSocket_client_applications)。

## 注意
标准库实现的性能极差。如果您计划不仅仅是进行基本的实验,请考虑使用替代库,例如:
- <https://github.com/karlseguin/http.zig>
- <https://github.com/zigzap/zap>
- <https://github.com/mookums/zzz>
12 changes: 12 additions & 0 deletions src/zh-CN/06-01-rand.smd
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
---
.title = "生成随机数",
.date = "2024-01-01",
.author = "ZigCC",
.layout = "section.shtml",
---

借助线程局部、加密安全的伪随机数生成器 [`std.crypto.random`] 生成随机数。

[]($code.siteAsset('src/06-01.zig').language('zig'))

[`std.crypto.random`]: https://ziglang.org/documentation/0.11.0/std/#A;std:crypto.random
18 changes: 18 additions & 0 deletions src/zh-CN/07-01-spawn.smd
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
---
.title = "启动短期线程",
.date = "2024-01-01",
.author = "ZigCC",
.layout = "section.shtml",
---

本示例使用 [`std.Thread`] 进行并发和并行编程。
[`std.Thread.spawn`] 启动一个新线程来计算结果。

此示例将数组分成两半,并在单独的线程中执行工作。

> 注意:为了确保当 `t2` 启动失败时 `t1` 线程已完成,我们在启动 `t1` 后立即 `defer t1.join()`。

[]($code.siteAsset('src/07-01.zig').language('zig'))

[`std.thread`]: https://ziglang.org/documentation/0.11.0/std/#A;std:Thread
[`std.thread.spawn`]: https://ziglang.org/documentation/0.11.0/std/#A;std:Thread.spawn
13 changes: 13 additions & 0 deletions src/zh-CN/07-02-shared-data.smd
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
---
.title = "在两个线程之间共享数据",
.date = "2024-01-01",
.author = "ZigCC",
.layout = "section.shtml",
---

当我们要修改线程之间共享的数据时,必须使用 [`Mutex`] (互斥锁) 来同步线程,否则结果可能出乎意料。

[]($code.siteAsset('src/07-02.zig').language('zig'))
如果我们移除互斥锁保护,结果很可能小于 30,000。

[`Mutex`]: https://ziglang.org/documentation/0.11.0/std/#A;std:Thread.Mutex
15 changes: 15 additions & 0 deletions src/zh-CN/07-03-threadpool.smd
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
---
.title = "线程池",
.date = "2024-01-01",
.author = "ZigCC",
.layout = "section.shtml",
---

线程池解决了两个不同的问题:
1. 在执行大量异步任务时,由于减少了每个任务的调用开销,它们通常提供更好的性能,并且
2. 它们提供了一种限制和管理在执行任务集合时消耗的资源(包括线程)的方法。


在此示例中,我们将 10 个任务放入线程池,并使用 `WaitGroup` 等待它们完成。

[]($code.siteAsset('src/07-03.zig').language('zig'))
11 changes: 11 additions & 0 deletions src/zh-CN/07-04-run-once.smd
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
---
.title = "运行一次",
.date = "2024-01-01",
.author = "ZigCC",
.layout = "section.shtml",
---


`std.once` 确保一个函数只执行一次,无论有多少个线程尝试调用它或它被调用多少次。这种线程安全的初始化对于单例模式和一次性设置操作特别有用。

[]($code.siteAsset('src/07-04.zig').language('zig'))
12 changes: 12 additions & 0 deletions src/zh-CN/08-01-cpu-count.smd
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
---
.title = "检查逻辑 CPU 核心数",
.date = "2024-01-01",
.author = "ZigCC",
.layout = "section.shtml",
---

使用 [`std.Thread.getCpuCount`] 显示当前机器中的逻辑 CPU 核心数。

[]($code.siteAsset('src/08-01.zig').language('zig'))

[`std.thread.getcpucount`]: https://ziglang.org/documentation/0.11.0/std/#A;std:Thread.getCpuCount
13 changes: 13 additions & 0 deletions src/zh-CN/08-02-external.smd
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
---
.title = "外部命令",
.date = "2024-01-01",
.author = "ZigCC",
.layout = "section.shtml",
---

通过 [`std.process.Child`] 运行外部命令,并通过 [pipe](管道)将输出收集到 `ArrayList` 中。

[]($code.siteAsset('src/08-02.zig').language('zig'))

[`std.process.child`]: https://ziglang.org/documentation/0.11.0/std/#A;std:process.Child
[pipe]: https://man7.org/linux/man-pages/man2/pipe.2.html
14 changes: 14 additions & 0 deletions src/zh-CN/09-01-semver.smd
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
---
.title = "解析版本字符串",
.date = "2024-01-01",
.author = "ZigCC",
.layout = "section.shtml",
---

使用 [`SemanticVersion.parse`] 从字符串字面量构造 [`std.SemanticVersion`]。

[]($code.siteAsset('src/09-01.zig').language('zig'))

[`std.semanticversion`]: https://ziglang.org/documentation/0.11.0/std/#A;std:SemanticVersion
[`semanticversion.parse`]: https://ziglang.org/documentation/0.11.0/std/#A;std:SemanticVersion.parse
[semantic versioning specification]: http://semver.org/
19 changes: 19 additions & 0 deletions src/zh-CN/10-01-json.smd
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
---
.title = "序列化和反序列化 JSON",
.date = "2024-01-01",
.author = "ZigCC",
.layout = "section.shtml",
---

[`std.json`] 提供了一组函数,如 [`stringify`] 和 [`stringifyAlloc`],用于序列化 JSON。
此外,我们可以使用 [`parseFromSlice`] 函数来解析 JSON 的 `[]u8`。

下面的示例显示了解析 JSON 的 `[]u8`。逐个比较每个成员。
然后,我们将 `verified` 字段修改为 `false`,并将其序列化回 JSON 字符串。

[]($code.siteAsset('src/10-01.zig').language('zig'))

[`std.json`]: https://ziglang.org/documentation/0.11.0/std/#A;std:json
[`stringify`]: https://ziglang.org/documentation/0.11.0/std/#A;std:json.stringify
[`stringifyalloc`]: https://ziglang.org/documentation/0.11.0/std/#A;std:json.stringifyAlloc
[`parsefromslice`]: https://ziglang.org/documentation/0.11.0/std/#A;std:json.parseFromSlice
23 changes: 23 additions & 0 deletions src/zh-CN/10-02-zon.smd
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
---
.title = "序列化和反序列化 ZON",
.date = "2024-01-01",
.author = "ZigCC",
.layout = "section.shtml",
---

ZON("Zig Object Notation")是一种文本文件格式。除了 `nan` 和 `inf` 字面量外,ZON 的语法是 Zig 语法的子集。

支持的 Zig 原语:
* 布尔字面量
* 数字字面量(包括 `nan` 和 `inf`)
* 字符字面量
* 枚举字面量
* `null` 字面量
* 字符串字面量
* 多行字符串字面量

支持的 Zig 容器类型:
* 匿名结构体字面量
* 匿名元组字面量

[]($code.siteAsset('src/10-02.zig').language('zig'))
15 changes: 15 additions & 0 deletions src/zh-CN/10-03-base64.smd
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
---
.title = "Base64 编码和解码",
.date = "2024-01-01",
.author = "ZigCC",
.layout = "section.shtml",
---

使用 [`std.base64.standard`] [`encode`] 将字节切片编码为 `base64` 字符串,并使用 [`standard`] [`decode`] 对其进行解码。

[]($code.siteAsset('src/10-02.zig').language('zig'))

[`std.base64.standard`]: https://ziglang.org/documentation/0.11.0/std/#A;std:base64.standard
[`standard`]: https://ziglang.org/documentation/0.11.0/std/src/std/base64.zig.html#L29
[`encode`]: https://ziglang.org/documentation/0.11.0/std/#A;std:base64.Base64Encoder.encode
[`decode`]: https://ziglang.org/documentation/0.11.0/std/#A;std:base64.Base64Decoder.decode
14 changes: 14 additions & 0 deletions src/zh-CN/11-01-complex-numbers.smd
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
---
.title = "创建和相加复数",
.date = "2024-01-01",
.author = "ZigCC",
.layout = "section.shtml",
---

创建 [`std.math.Complex`] 类型的复数。复数的实部和虚部必须是相同的类型。

对复数执行数学运算与对内置类型执行数学运算相同:相关数字必须是相同的类型(即浮点数或整数)。

[]($code.siteAsset('src/11-01.zig').language('zig'))

[`std.math.complex`]: https://ziglang.org/documentation/0.11.0/std/#A;std:math.Complex
Loading