#Close unix socket

1 messages · Page 1 of 1 (latest)

dense granite
#

I want to create a program with a client-server architecture. So I thought of using a local socket to allow for ipc. Here is an example code of what I am doing:

server.zig

const std = @import("std");

pub fn main() !void {
    const address = try std.net.Address.initUnix("test.sock");
    var server = try address.listen(.{
        .reuse_port = true,
        .reuse_address = true,
    });
    defer server.deinit();

    std.debug.print("[INFO] Server listening on {}\n", .{address});

    var buffer: [512]u8 = undefined;

    while (true) {
        const connection = try server.accept();

        const len = try connection.stream.read(&buffer);
        std.debug.print(
            "[INFO] Received {d} bytes from client - {s}\n",
            .{ len, buffer[0..len] },
        );

        _ = try connection.stream.write("Hello from server");

        connection.stream.close();
    }
}

The problem is that the test.sock file remains there after I kill the process.
So if I try and re-run zig run server.zig it fails with error: AddressInUse

How should I handle this?

timber vigil
dense granite
#

How do I close it? That server.deinit() does not seem to be working.

Here is the code I am using:

const std = @import("std");

pub fn main() !void {
    const address = try std.net.Address.initUnix("test.sock");
    var server = try address.listen(.{
        .reuse_port = true,
        .reuse_address = true,
    });
    defer server.deinit();
}
timber vigil
#

are you killing the process before the deinit() runs? defer/errdefer just moves things to the end of the scope but a process terminating by a signal stops wherever it was without returning / cleaning up the scope

dense granite
#

I understood that the SIGINT does not allow the program to call the defered blocks. But removing the loop and allowing the program to run the defer server.deinit() still leaves the socket there

#

I am not killing the process. In the last code snippet 🙄 there is no loop, so the process end immediately without me sending any signal

timber vigil
dense granite
#

I found the std.os.sigaction function, but I have no idea on how to pass the server to the handler function

finite mantle
#

signal handlers are one of the few situations where globals are justified (and only cuz there's no other way to do it heh)

dense granite
#

The test.sock file is still there after handling SIGINT. Here is the code I am using:

const std = @import("std");

var server: std.net.Server = undefined;

fn handleSigint(_: c_int) callconv(.C) void {
    server.deinit();
    std.debug.print("Handling SIGINT\n", .{});
    std.process.exit(0);
}

pub fn main() !void {
    const address = try std.net.Address.initUnix("test.sock");
    server = try address.listen(.{
        .reuse_port = true,
        .reuse_address = true,
    });
    errdefer server.deinit();

    try std.os.sigaction(std.os.SIG.INT, &.{
        .handler = .{.handler = handleSigint},
        .mask = std.os.empty_sigset,
        .flags = 0,
    }, null);

    std.debug.print("[INFO] Server listening on {}\n", .{address});

    var buffer: [512]u8 = undefined;

    while (true) {
        const connection = try server.accept();

        const len = try connection.stream.read(&buffer);
        std.debug.print(
            "[INFO] Received {d} bytes from client - {s}\n",
            .{ len, buffer[0..len] },
        );

        _ = try connection.stream.write("Hello from server");

        connection.stream.close();
    }
}
timber vigil
finite mantle
#

yeah, signals becoming events is wayyyy better than interrupts imo

#

signalfd my beloved <3

rigid trail
finite mantle
#

you mean like closures?

#

yeah, zig doesn't have runtime closures, for good reason