-
-
Save andrewrk/34c21bdc1600b0884a3ab9fa9aa485b8 to your computer and use it in GitHub Desktop.
| const std = @import("std"); | |
| const net = std.net; | |
| const fs = std.fs; | |
| const os = std.os; | |
| pub const io_mode = .evented; | |
| pub fn main() anyerror!void { | |
| var general_purpose_allocator = std.heap.GeneralPurposeAllocator(.{}){}; | |
| const allocator = &general_purpose_allocator.allocator; | |
| var server = net.StreamServer.init(.{}); | |
| defer server.deinit(); | |
| // TODO handle concurrent accesses to this hash map | |
| var room = Room{ .clients = std.AutoHashMap(*Client, void).init(allocator) }; | |
| try server.listen(net.Address.parseIp("127.0.0.1", 0) catch unreachable); | |
| std.debug.warn("listening at {}\n", .{server.listen_address}); | |
| while (true) { | |
| const client = try allocator.create(Client); | |
| client.* = Client{ | |
| .conn = try server.accept(), | |
| .handle_frame = async client.handle(&room), | |
| }; | |
| try room.clients.putNoClobber(client, {}); | |
| } | |
| } | |
| const Client = struct { | |
| conn: net.StreamServer.Connection, | |
| handle_frame: @Frame(handle), | |
| fn handle(self: *Client, room: *Room) !void { | |
| try self.conn.file.writeAll("server: welcome to teh chat server\n"); | |
| while (true) { | |
| var buf: [100]u8 = undefined; | |
| const amt = try self.conn.file.read(&buf); | |
| const msg = buf[0..amt]; | |
| room.broadcast(msg, self); | |
| } | |
| } | |
| }; | |
| const Room = struct { | |
| clients: std.AutoHashMap(*Client, void), | |
| fn broadcast(room: *Room, msg: []const u8, sender: *Client) void { | |
| var it = room.clients.iterator(); | |
| while (it.next()) |entry| { | |
| const client = entry.key; | |
| if (client == sender) continue; | |
| client.conn.file.writeAll(msg) catch |e| std.debug.warn("unable to send: {}\n", .{e}); | |
| } | |
| } | |
| }; |
| Tested with zig 0.6.0+4e63ca. The latest master branch build | |
| from https://ziglang.org/download/ should work just fine. | |
| zig build-exe basic-tcp-chat.zig | |
| ./basic-tcp-chat | |
| This will print "listening at listening at 127.0.0.1:$PORT" | |
| To play with it you have to open 2 terminal windows and in each one | |
| (replacing $PORT with the one printed): | |
| nc 127.0.0.1 $PORT | |
| Now the terminals can talk to each other when you type your message and press enter. |
https://gist.github.com/karlseguin/53bb8ebf945b20aa0b7472d9d30de801
Works in 0.9.0, gives each client an arena, and cleans up after clients disconnect (Using a queue to track arenas that need to be cleaned up doesn't seem ideal to me, but it was the only solution I could come up with (and I saw it used in a few other libraries, so...))
builds https://gist.github.com/rofrol/55de5a3be4b2ec531ba3e85d2bdcb0a5 but does not show entered message
Can someone help to get this working in Zig 0.12.0? All APIs changed :(.
@renatoathaydes I've updated my fork to work with 0.12
@renatoathaydes I've updated my fork to work with 0.12
@karlseguin thanks
Fork of @karlseguin which formats messages like Client<id>: msg https://github.com/rofrol/basic-tcp-chat-in-zig
Another one! https://gist.github.com/pwbh/b404d1096e553676933f93ff307e25fc (Zig 0.12)
Here is an updated version for the current Zig version (tested with 0.9.0-dev.23+c313e3f50):
https://gist.github.com/marijnfs/78b0cc13d76a19dffbced766726189ec