Hello,
I’m trying to make a little game so naturally I decided to use udp for networking. The issue is, that my code just plain does not work. A previous example of my server is able to communicate to nc -u “::1“ 1234(it turns out that it can no longer send messages back but it receives them fine, I dont know why), but the example below which is a minimal version of my games relevant code does not work. I just blocks. Changing to force_nonblocking = true does not change that.
I am not experienced with udp by any means and part of this code is currently a mixture of zigs stdlib and translated c code as I am just trying to do a basic echo within at the moment.
const std = @import("std");
pub const addr_len: u32 = @sizeOf(std.posix.sockaddr);
pub const Server = struct {
address: std.net.Address,
socket: std.posix.socket_t,
const Options = struct {
client_only: bool = false,
force_nonblocking: bool = false,
reuse_address: bool = false,
};
pub fn fromAddress(address: std.net.Address, options: Options) !Server {
const nonblock: u32 = if (options.force_nonblocking) std.posix.SOCK.NONBLOCK else 0;
const flags = std.posix.SOCK.DGRAM | nonblock;
const socket = try std.posix.socket(address.any.family, flags, 0);
if (options.reuse_address) {
try std.posix.setsockopt(
socket,
std.posix.SOL.SOCKET,
std.posix.SO.REUSEADDR,
&std.mem.toBytes(@as(c_int, 1)),
);
}
if (!options.client_only) {
try std.posix.bind(socket, &address.any, address.getOsSockLen());
}
return .{
.address = address,
.socket = socket,
};
}
pub fn deinit(self: *Server) void {
std.posix.close(self.socket);
self.* = undefined;
}
pub fn receive(self: *Server, buf: []u8) !struct { std.net.Address, []const u8 } {
var source: std.net.Address = self.address;
const read_len = try std.posix
.recvfrom(self.socket, buf, 0, &source.any, @constCast(&addr_len));
return .{ source, buf[0..read_len] };
}
pub fn send(self: *const Server, destination: std.net.Address, message: []const u8) !void {
_ = try std.posix.sendto(self.socket, message, 0, &destination.any, addr_len);
}
};
pub fn main() !void {
const server_addr: std.net.Address = try .resolveIp("::1", 1234);
var server_thread: std.Thread = try .spawn(.{}, serverThread, .{server_addr});
defer server_thread.join();
std.Thread.sleep(std.time.ns_per_s);
const client_addr: std.net.Address = try .resolveIp("::1", 0);
var client: Server = try .fromAddress(client_addr, .{});
defer client.deinit();
try client.send(server_addr, "feef");
}
fn serverThread(addr: std.net.Address) !void {
var server: Server = try .fromAddress(addr, .{ .force_nonblocking = false });
defer server.deinit();
var buf: [0x1000]u8 = undefined;
while (true) {
const source, const bytes = server.receive(&buf) catch |e| switch (e) {
error.WouldBlock => {
std.Thread.sleep(std.time.ns_per_s); // smite me
continue;
},
else => return e,
};
try server.send(source, bytes);
std.debug.print("{f} {s}", .{ source, bytes });
}
}