UDP Socket Server in Zig

I am trying to create UDP Server in Zig however I am encountering an error what I am not sure how to fix.

const server_ip = try net.Address.parseIp("127.0.0.1", 55555);
const sockfd = try os.socket(server_ip.any.family, os.SOCK.DGRAM, 0);
var s: net.Server = .{
    .listen_address = undefined,
    .stream = .{ .handle = sockfd },
};
errdefer s.deinit();

try os.setsockopt(
    sockfd,
    os.SOL.SOCKET,
    os.SO.REUSEADDR,
    &std.mem.toBytes(@as(c_int, 1)),
);

try os.bind(sockfd, &server_ip.any, server_ip.getOsSockLen());
try os.listen(sockfd, @as(u31, 128));
debugPrint("Server Listerning on {any}\n", .{server_ip});

I get the error error: OperationNotSupported at line try os.listen(sockfd, @as(u31, 128));

This code works if I use os.SOCK.STREAM instead.

2 Likes

The listen call is used to accept connections for connection based sockets.

listen() marks the socket referred to by sockfd as a passive socket, that is, as a socket that will be used to accept incoming connection requests using accept(2).

The sockfd argument is a file descriptor that refers to a socket of type SOCK_STREAM or SOCK_SEQPACKET.

For connectionless sockets like a UDP socket you instead need to use something like recvfrom to read messages directly from the given socket. The Zig standard library has os.recvfrom.

5 Likes

The following is a working example that wait for one packet, displays it and exits.

const std = @import("std");

pub fn main() !void {
    const addr = try std.net.Address.parseIp("127.0.0.1", 55555);
    const sock = try std.os.socket(std.os.AF.INET, std.os.SOCK.DGRAM, std.os.IPPROTO.UDP);
    defer std.os.close(sock);
    try std.os.bind(sock, &addr.any, addr.getOsSockLen());
    var buf: [1024]u8 = undefined;
    const len = try std.os.recv(sock, &buf, 0);
    std.debug.print("{s}\n", .{buf[0..len]});
}

EDIT: You can use recvfrom to get the IP address and port of the remote party.

6 Likes