Zig Cookbook

介绍

监听未使用的 TCP/IP 端口

在此示例中,端口显示在控制台上,程序将监听直到收到请求。使用 IpAddress 配合 .loopback(0) 会分配一个随机端口。

//! Start an echo TCP server at an unused port.
//!
//! Test with
//! echo "hello zig" | nc localhost <port>

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

pub fn main(init: std.process.Init) !void {
    const io = init.io;

    const loopback: net.IpAddress = .{ .ip4 = .loopback(0) };
    var server = try loopback.listen(io, .{
        .reuse_address = true,
    });
    defer server.deinit(io);

    const addr = server.socket.address;
    print("Listening on {f}, access this port to end the program\n", .{addr});

    const stream = try server.accept(io);
    // In real world, you'd want to handle multiple clients, probably in separate threads.
    try handleClient(stream, io);
}

fn handleClient(stream: net.Stream, io: Io) !void {
    defer stream.close(io);
    var stream_buf: [1024]u8 = undefined;
    var reader = stream.reader(io, &stream_buf);
    // Here we echo back what we read directly, so the writer buffer is empty
    var writer = stream.writer(io, &.{});

    while (true) {
        print("Waiting for data...\n", .{});
        const msg = reader.interface.takeDelimiterInclusive('\n') catch |err| {
            if (err == error.EndOfStream) {
                print("Client closed the connection\n", .{});
                return;
            } else {
                return err;
            }
        };
        print("Client says {s}", .{msg});
        try writer.interface.writeAll(msg);
        // No need to flush, as writer buffer is empty
    }
}

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

echo "hello zig" | nc localhost <port>

默认情况下,程序使用 IPv4 进行监听。如果您想要 IPv6,请使用 net.IpAddress{ .ip6 = .loopback(0) } 代替。

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

下一节将演示如何使用 Zig 代码连接到此服务器。