State of UDP networking support?

It’s been a few Zig versions since I last did any UDP networking, and back then I used the zig-network library to abstract away the platform-specific implementations.

But now, looking again at Zig 0.15 and possibly 0.16, I’m curious how much is natively available without the need for a library.

  • std.net looks nice, but it appears to be TCP only
  • Does UDP usage still require dropping to std.posix? What about on Windows?
  • Is std.Io bringing more net functionality in 0.16?

Also, it looks like the zio library is getting a lot of attention as an I/O alternative, and has network functionality built-in. Is this because support is still lacking in the standard library? Or is zio more like a difference of opinion on API design from Zig?

I’ve used Zig std.Io for making a small udp server for streaming h264, as a side project, don’t know if that helps : ustream Probably doesn’t compile with current master if I had to guess.

1 Like

I’m the author, so I can answer this.

When I started, std was heavily lacking in networking. The networking capabilities it had were fine for the use case of the compiler, but any external project that was usable in production had their own networking layer.

I didn’t want to write another asynchronous networking layer for my application alone, so I invested time into zio. From the ground up it’s built with servers in mind.

You can already use zio with the std.Io APIs. As the interface matures, maybe it will become the only API. Even the native zio APIs are heavily based on std.Io to simplify the migration. Once 0.16 is released, the I’ll start shifting more into just an implementation of the interface.

But I believe the the architecture of zio is already better than the planned std.Io.Evented in terms of design for writing server applications, so the runtime will stay.

3 Likes

I’m using UDP in my project for 0.16.0-dev.
In case you want to see it:

but here are the parts of the code from there:
It uses receive and send:

std.Io.net.Socket.receive(wg_sock, io, buf[0..])
std.Io.net.Socket.send(serv_sock, io, &servers[current_id.*], packet)

Port creation:

    // WireGuard -> Forwarder
    const wg_listen_addr = try std.Io.net.IpAddress.parse(
        config.client_endpoint.address,
        config.client_endpoint.port,
    );

    // Forwarder
    const fw_listen_addr = try std.Io.net.IpAddress.parse(
        config.forwarder_socket.address,
        config.forwarder_socket.port,
    );

    // Listen for WireGuard (client) packets
    var wg_sock = try std.Io.net.IpAddress.bind(&fw_listen_addr, io, .{
        .ip6_only = false,
        .mode = .dgram,
        .protocol = .udp,
    });

    // Server -> Forwarder
    const server_listen_addr = try std.Io.net.IpAddress.parse(
        config.server_socket.address,
        config.server_socket.port,
    );
    // Listen for Server packets
    var serv_sock = try std.Io.net.IpAddress.bind(&server_listen_addr, io, .{
        .ip6_only = false,
        .mode = .dgram,
        .protocol = .udp,
    });

And address formatting:

    // Format read endpoints
    var servers = try allocator.alloc(std.Io.net.IpAddress, config.switcher.endpoints.len);
    defer allocator.free(servers);
    for (config.switcher.endpoints, 0..) |s, i| {
        var split: std.ArrayList([]const u8) = .empty;
        defer split.deinit(allocator);
        var iter = std.mem.splitScalar(u8, s, ':');
        while (iter.next()) |part| {
            try split.append(allocator, part);
        }
        const ip = split.items[0];
        const port = try std.fmt.parseInt(u16, split.items[1], 10);
        servers[i] = try std.Io.net.IpAddress.parse(ip, port);
    }
4 Likes

Thanks for the reply! I gotta say, zio is looking very tempting, beyond just networking. :slight_smile:

Very helpful, thank you!

Edit: So it look like Zig has all the necessary pieces, but they’re still mostly within posix rather than having platform-specific implementations.

1 Like

3 posts were merged into an existing topic: Zio - async I/O framework

FWIW, here’s another example for UDP networking based on std.Io.net : Reflected, the huge mahogany. Before, I had similar functionality from std.net and std.posix.

Now especially std.posix is not required anymore, std.Io.net only draws very minimally from it. All in all, the new variant seems leaner to me but also seems to give you less control (which I don’t miss).