4

By looking at the docs of zig's standard library I found out that it actually does have some functions for socket programming. But I just don't know how to use them as they are not documented completely.

To create a socket, one can use std.os.socket() function which takes three arguments: domain, socket_type, protocol. They are all of type u32. Now I have done socket programming in Python. In python there are some predefined variables like socket.AF_INET and socket.SOCK_STREAM which you can use as argument for the socket.socket function which takes address_family and protocol arguments. But I couldn't find such variables in zig's docs so I don't know what should be the value of these arguments.

Also After defining the socket using os.socket() function, one can use os.bind() function which takes 3 arguments: sock, addr, len. obviously sock is the created socket but what should be supplied as address and length? I'm also baffled about os.accept() function. it takes addr, addr_size and flags arguments. I have no idea what values should go there too.

1
  • 3
    All of those functions are one-to-one ports of the like-named POSIX C functions in the BSD Sockets API, which you can read the man page of by googling e.g. "man accept" (or if you're on MacOS or Linux, by entering e.g. "man accept" into a shell window). That documentation will tell you what the arguments are for and what they do, so then the remaining part of the problem is just figuring out how to express them in zig. Commented Sep 13, 2023 at 12:48

2 Answers 2

3

file: client.zig

const std = @import("std");
const net = std.net;

const addr = net.Address.initIp4(.{ 127, 0, 0, 1 }, 7496);

pub fn eclient() !void {
    const options = net.StreamServer.Options{};
    var server = net.StreamServer.init(options);
    // Listening
    _ = try server.listen(addr);

    std.debug.print("Server is listening on: {any}\n", .{addr});
    while (true) {
        const client = try server.accept();
        const client_addr = client.address;
        const stream = client.stream;

        // Buffer for read
        var buffer: [256]u8 = undefined;

        _ = try stream.read(&buffer);
        _ = try stream.write("Hi there!");

        std.debug.print("client addr is : {any}\n", .{client_addr});
        std.debug.print("request buffer is : {s}\n", .{buffer});
    }
}

file: main.zig

const std = @import("std");
const client = @import("client.zig");

pub fn main() !void {
    const result = client.eclient();
    _ = try result;
}
Sign up to request clarification or add additional context in comments.

Comments

1

You might not have to go to such a low level. The following code

const raw_listen_address = std.os.getenv("LISTEN_ADDRESS") orelse return error.MissingListenAddress;
const listen_address = if (std.mem.startsWith(u8, raw_listen_address, "unix://"))
    try std.net.Address.initUnix(raw_listen_address[7..])
else if (std.mem.startsWith(u8, raw_listen_address, "tcp://")) blk: {
    const raw = raw_listen_address[6..];
    const index = std.mem.indexOfScalar(u8, raw, ':');
    if (index) |i| {
        var address = try std.net.Address.parseIp(raw[0..i], 0);
        const port = try std.fmt.parseUnsigned(u16, raw[i + 1 ..], 10);
        address.setPort(port);
        break :blk address;
    } else {
        break :blk try std.net.Address.parseIp(raw, 0);
    }
} else {
    return error.InvalidListenAddress;
};

converts the environment variable LISTEN_ADDRESS in a listen address of type std.net.Address. The address can be eight specified as unix:///var/run/service.sock or tcp://127.0.0.1:5000.

The result can be passed to a std.net.StreamServer.

const stream_server = std.net.StreamServer.init(.{});
try self.stream_server.listen(listen_address);

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.