实战:Zig 编写高性能 Web 服务(1)

1.1  认识 std.http

std.http 是 Zig 标准库中用于处理 HTTP 相关操作的类库。以我学习新的编程语言的经历来看,编写web程序是最常见的技术场景,所以熟练掌握 HTTP server/client 服务相关的编程知识是比较重要的。

std.http 主要包含以下API:

  • Client: HTTP client implementation.
  • Server: HTTP server implementation.
  • protocol:headers parse methods.
  • Connection: Connection type (keep_aliveclose)
  • ContentEncoding: Content encoding options (compressdeflategzip and zstd)
  • Field: Common type for name and value
  • Headers: HTTP headers
  • Method: HTTP methods such as GET and POST
  • Status: HTTP status codes (not_found = 404teapot = 418, etc.)
  • TransferEncoding: Form of encoding used to transfer the body (chunked)
  • Version: Currently HTTP/1.0 and HTTP/1.1

1.2 编写一个HTTP client程序

先创建一个开工项目:

$ mkdir -p httpz
$ cd httpz
$ zig init

$ ls -ls
total 20
4 -rw-r--r-- 1 xiaods xiaods 3879 Jun  3 11:53 build.zig
4 -rw-r--r-- 1 xiaods xiaods 3080 Jun  3 11:50 build.zig.zon
4 drwxr-xr-x 2 xiaods xiaods 4096 Jun  3 13:33 src
4 drwxr-xr-x 6 xiaods xiaods 4096 Jun  3 11:51 zig-cache
4 drwxr-xr-x 4 xiaods xiaods 4096 Jun  3 11:51 zig-out

编辑 src/main.zig,我们将使用 std.heap.GeneralPurposeAllocator,这是一个安全的分配器,可以防止双重释放(double-free)、使用后释放(use-after-free),并且能够检测内存泄漏。

const std = @import("std");
const print = std.debug.print;
const http = std.http;

    var gpa = std.heap.GeneralPurposeAllocator(.{}){};
    defer _ = gpa.deinit();
    const allocator = gpa.allocator();

下一步,为了发送一个请求,我们需要几样东西:

  • client.open 函数
  • 一个从URL解析而来的 std.Uri

下面是我们如何将这些参数组合在一起的方法:

    const uri = try std.Uri.parse("http://httpbin.org/headers");
    const buf = try allocator.alloc(u8, 1024 * 1024 * 4);
    defer allocator.free(buf);
    var req = try client.open(.GET, uri, .{
        .server_header_buffer = buf,
    });
    defer req.deinit();

为了真正的发送请求,需要通过send,finish,wait来完成:

 try req.send();
 try req.finish();
 try req.wait();

打印返回的服务器headers 信息:

var iter = req.response.iterateHeaders();
    while (iter.next()) |header| {
        std.debug.print("Name:{s}, Value:{s}\n", .{ header.name, header.value });
    }

    try std.testing.expectEqual(req.response.status, .ok);

打印返回的服务端内容:

    var rdr = req.reader();
    const body = try rdr.readAllAlloc(allocator, 1024 * 1024 * 4);
    defer allocator.free(body);

    print("Body:\n{s}\n", .{body});

把上面的代码所有内容放在一起,并打印出响应内容:

const std = @import("std");
const print = std.debug.print;
const http = std.http;

pub fn main() !void {
    var gpa = std.heap.GeneralPurposeAllocator(.{}){};
    defer _ = gpa.deinit();
    const allocator = gpa.allocator();

    var client = http.Client{ .allocator = allocator };
    defer client.deinit();

    const uri = try std.Uri.parse("http://httpbin.org/headers");
    const buf = try allocator.alloc(u8, 1024 * 1024 * 4);
    defer allocator.free(buf);
    var req = try client.open(.GET, uri, .{
        .server_header_buffer = buf,
    });
    defer req.deinit();

    try req.send();
    try req.finish();
    try req.wait();

    var iter = req.response.iterateHeaders();
    while (iter.next()) |header| {
        std.debug.print("Name:{s}, Value:{s}\n", .{ header.name, header.value });
    }

    try std.testing.expectEqual(req.response.status, .ok);

    var rdr = req.reader();
    const body = try rdr.readAllAlloc(allocator, 1024 * 1024 * 4);
    defer allocator.free(body);

    print("Body:\n{s}\n", .{body});
}

跑一下:

 $ zig build run
Name:Date, Value:Mon, 03 Jun 2024 08:24:19 GMT
Name:Content-Type, Value:application/json
Name:Content-Length, Value:202
Name:Connection, Value:keep-alive
Name:Server, Value:gunicorn/19.9.0
Name:Access-Control-Allow-Origin, Value:*
Name:Access-Control-Allow-Credentials, Value:true
Body:
{
  "headers": {
    "Accept-Encoding": "gzip, deflate",
    "Host": "httpbin.org",
    "User-Agent": "zig/0.12.0 (std.http)",
    "X-Amzn-Trace-Id": "Root=1-665d7db3-258c846d0fcca0912fadfa8b"
  }
}

成功了!我们成功地向服务器发送了一个GET请求并打印出了响应。

GET请求的例子我们看到了,那么如何发起POST请求呢?让我们继续拿例子说话。

准备好发送内容:

const uri = try std.Uri.parse("http://httpbin.org/anything");

    const payload =
        \\ {
        \\  "name": "zig-learning",
        \\  "author": "xiaods"
        \\ }
    ;

发送POST 请求:

var buf: [1024]u8 = undefined;
    var req = try client.open(.POST, uri, .{ .server_header_buffer = &buf });
    defer req.deinit();

    req.transfer_encoding = .{ .content_length = payload.len };
    try req.send();
    var wtr = req.writer();
    try wtr.writeAll(payload);
    try req.finish();
    try req.wait();

    try std.testing.expectEqual(req.response.status, .ok);

打印返回内容:

var rdr = req.reader();
    const body = try rdr.readAllAlloc(allocator, 1024 * 1024 * 4);
    defer allocator.free(body);

    print("Body:\n{s}\n", .{body});

完整的Post代码如下:

const std = @import("std");
const print = std.debug.print;
const http = std.http;

pub fn main() !void {
    var gpa = std.heap.GeneralPurposeAllocator(.{}){};
    defer _ = gpa.deinit();
    const allocator = gpa.allocator();

    var client = http.Client{ .allocator = allocator };
    defer client.deinit();

    const uri = try std.Uri.parse("http://httpbin.org/anything");

    const payload =
        \\ {
        \\  "name": "zig-learning",
        \\  "author": "xiaods"
        \\ }
    ;

    var buf: [1024]u8 = undefined;
    var req = try client.open(.POST, uri, .{ .server_header_buffer = &buf });
    defer req.deinit();

    req.transfer_encoding = .{ .content_length = payload.len };
    try req.send();
    var wtr = req.writer();
    try wtr.writeAll(payload);
    try req.finish();
    try req.wait();

    try std.testing.expectEqual(req.response.status, .ok);

    var rdr = req.reader();
    const body = try rdr.readAllAlloc(allocator, 1024 * 1024 * 4);
    defer allocator.free(body);

    print("Body:\n{s}\n", .{body});
}

 运行结果:

$ zig run src/http-post.zig 
Body:
{
  "args": {}, 
  "data": " {\n  \"name\": \"zig-learning\",\n  \"author\": \"xiaods\"\n }", 
  "files": {}, 
  "form": {}, 
  "headers": {
    "Accept-Encoding": "gzip, deflate", 
    "Content-Length": "52", 
    "Host": "httpbin.org", 
    "User-Agent": "zig/0.12.0 (std.http)", 
    "X-Amzn-Trace-Id": "Root=1-665d8114-01b0167844d8d101012e6d6a"
  }, 
  "json": {
    "author": "xiaods", 
    "name": "zig-learning"
  }, 
  "method": "POST", 
  "origin": "219.133.170.77", 
  "url": "http://httpbin.org/anything"
}

请消化消化以上代码,别着急,我们后面继续前行,编写web server

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/676603.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

19、matlab信号预处理中的中值滤波(medfilt1()函数)和萨维茨基-戈雷滤波滤(sgolayfilt()函数)

1、中值滤波:medfilt1()函数 说明:一维中值滤波 1)语法 语法1:y medfilt1(x) 将输入向量x应用3阶一维中值滤波器。 语法2:y medfilt1(x,n) 将一个n阶一维中值滤波器应用于x。 语法3:y medfilt1(x,n…

Django中使用ModelForm保存数据

相对来说,使用ModelForm保存数据在Django中算是比较简单的。主要原因是ModelForm是建立在Django的模型(Model)之上的,它可以自动根据模型的定义生成表单,包括字段和验证规则。这样可以大大简化开发人员处理表单数据的工…

低空经济发展报告

低空经济是指利用低空空间进行商业开发和经济活动的概念。随着航空技术的发展和无人机的普及,低空经济逐渐成为一个新兴的经济领域。 低空经济可以涵盖的领域非常广泛,包括但不限于物流配送、农业植保、城市交通、旅游观光等。利用无人机等飞行器进行物…

C\C++内存管理(未完结)

文章目录 一.C\C内存分布二.C语言中动态内存管理方式:malloc/calloc/realloc/free三.C内存管理方式3.1.new/delete操作内置类型3.2.new和delete操作自定义类型 四.operator new与operator delete函数(重要点进行讲解)4.1. operator new与oper…

MySQL—约束—演示(基础)

一、引言 这篇博客主要演示:前面博客在约束概念与分类中讲到的:非空约束、唯一约束、检查约束、默认约束、主键约束、外键约束等等操作。 二、需求 根据下列需求,去完成表结构的创建。 注意:(对于一个字段我们可以添…

语言模型解构——Tokenizer

1. 认识Tokenizer 1.1 为什么要有tokenizer? 计算机是无法理解人类语言的,它只会进行0和1的二进制计算。但是呢,大语言模型就是通过二进制计算,让你感觉计算机理解了人类语言。 举个例子:单1,双2&#x…

新农大杏之所向,心之所往团队实地调研与行动

南疆实地调研背景 近期,我团队前往南疆的喀什、和田地区,深入英吉沙县调研“赛买提”杏农民采摘后的收益情况。调研中发现,由于“赛买提”杏属于呼吸跃变型水果,采摘后呼吸作用加剧,加之收获季节易受链格孢侵染引起的…

DevOps后时代,构建基于价值流的平台化工程

本文来自腾讯蓝鲸智云社区用户: CanWay 平台化工程涉及双重核心意义。一方面,是类似利用IDE等工具提高工程师效率的平台化工程,如GitOps或命令行调度般便捷。然而,本文重点探讨的是基于价值流的平台化工程,尤其针对传统金融行业&a…

家宽动态公网IP,使用docker+ddns 实现动态域名解析

官方地址:https://github.com/jeessy2/ddns-go 安装docker docker pull jeessy/ddns-godocker run -d --name ddns-go --restartalways --nethost -v /opt/ddns-go:/root jeessy/ddns-go然后访问ip端口 配置时注意如下

剪画小程序:音频提取:学会这个方法可以提取任何音频!

我是测试了几天,发现是真的好用,所以写了这篇文章给宝子们做下分享 现在各大主流音乐平台都要开通会员才能听取完整版的歌曲, 有些歌甚至只能一个平台上播放,需要来回切换不同的音乐平台十分麻烦 当你正想将这首歌曲收藏到歌单…

常见的激活函数(sigmoid、tanh、ReLU、Leaky ReLU、P-ReLU、R-ReLU、ELU、Swish、Mish、Maxout、softmax)

文章目录 前言求导四则运算法则基本初等函数的导数sigmoid函数sigmoid函数适用场景sigmoid函数图像sigmoid函数的导数公式sigmoid函数的导数图像sigmoid函数的缺点解决办法 tanh函数tanh函数公式推导过程tanh函数图像tanh函数的导数公式tanh函数的导数图像 t a n h ( x ) 1 2…

Java编程常见问题汇总二

系列文章目录 文章目录 系列文章目录前言一、请使用XML解析器二、请使用JDom组装XML三、XML编码陷阱四、未指定字符编码五、未对数据流进行缓存 前言 前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击…

Python知识总结

对python知识的梳理,主要是平时的web开发的一些经验。其中比如使用gevent协程,celery异步任务队列,schema,sqlalchemy都是有非常多知识点可以单独讲的。其实python的web开发还有一项我觉得重要的方面是设计模式,这个就可以从其它书里学习了&a…

python小练习03

1.绘制奥运五环旗 #奥运五环的绘制 import turtle as t t.pensize(3) t.speed(0) def draw_circles():i0while i <4:args [[-60,0,"blue"],[0,0,"black"],[60,0,"red"],[-30,-30,"yellow"],[30,-30,"green"]]#定义一个…

k8s怎么监听自定义资源的变更?(1)

这里我们通过 k8s的 code-generate来生成操作自定义资源的代码来监听变更 第一步下载工具 下载安装 k8s code-generate 查看我们的k8s版本 kubectl get node 输出结果为 可以看到我们的k8s版本为 v1.22.0 所以此时我们要下载与之对应的版本的code-generate git clone htt…

Spring Cache自定义序列化解决乱码问题

Spring Cache数据缓存到 Redis中的 value是乱码问题&#xff08;包含日期格式转换&#xff09;&#xff0c;主要是因为序列化方式导致的。 Spring Cache使用 Redis缓存管理器时&#xff0c;默认 value使用的是 JDK序列化值的方式&#xff0c;所以导致缓存的 value乱码的问题。 …

【Java面试】十、微服务篇-分布式(下)

文章目录 1、分布式系统2、CAP定理3、Base理论4、分布式事务的解决方案&#xff1a;Seata4.1 Seata的XA模式4.2 Seata的AT模式4.3 Seata的TCC模式 5、分布式事务的解决方案&#xff1a;MQ6、分布式系统下&#xff0c;接口的幂等性6.1 数据库唯一索引6.2 token redis6.3 分布式…

MATLAB和物联网连载1:Internet of Things离你有多远?5行MATLAB的距离

MATLAB和物联网连载1:Internet of Things离你有多远?5行MATLAB的距离 原文&#xff1a;MATLAB和物联网连载1:Internet of Things离你有多远?5行MATLAB的距离 - 知乎 (zhihu.com) 来自俄罗斯的实习生在工作之余喜欢上网看点有的没的。有一天他突然发现了一个神奇的网站叫 T…

HTTP --tcp和keep-alive

TCP TCP连接 tcp/ip是全球计算机以及网络设备都在使用的一种常见的分组交换网络分层协议集&#xff0c;客户端可以打开一条tcp/ip连接&#xff0c;连接到可能运行在世界各地的服务器应用程序&#xff0c;一旦连接建立起来了&#xff0c;在客户端和服务器的计算机之间交换的报…

IntelliJ IDEA配置创建文件后自动生成注释字段,包括作者、日期和描述等信息。

效果 新建文件自动生成如下文档注释 配置如下&#xff1a; 打开setting 进行如下操作 粘贴的模板内容如下&#xff1a; /*** author developer_ZhangXinHua* date ${YEAR}/${MONTH}/${DAY}* desc ${DESCRIPTION}*/