AsyncZocket is a comprehensive WebSocket library for the Zig programming language, providing both client and server implementations. Built on the xev
event loop library for high-performance asynchronous I/O operations, it offers a robust foundation for real-time communication applications. The library supports the full WebSocket protocol (RFC 6455) and can handle multiple concurrent connections efficiently on a single thread.
- Full RFC 6455 Compliance: Complete implementation of the WebSocket protocol specification
- Frame Types: Support for Text, Binary, Close, Ping, and Pong frames
- Proper Masking: Client-side frame masking and server-side unmasking
- Control Frame Handling: Automatic Ping/Pong responses and proper Close handshake
- Non-blocking Client: Asynchronous WebSocket client with connection queuing
- Connection Management: Automatic reconnection and connection state tracking
- Write Queuing: Buffers write operations before connection establishment
- Flexible Configuration: Configurable host, port, and path parameters
- High-Performance Server: Multi-client server with configurable connection limits
- Connection Pooling: Efficient management of concurrent client connections
- Callback-Based API: Event-driven architecture with customizable handlers
- Asynchronous I/O: Built entirely on
xev
for non-blocking operations - Memory Efficient: Smart buffer management and connection pooling
- Single-Threaded: Efficient event-loop based concurrency model
Use fetch:
zig fetch --save https://github.com/Thomvanoorschot/async_zocket/archive/main.tar.gz
Or add AsyncZocket to your build.zig.zon
:
.dependencies = .{
.async_zocket = .{
.url = "https://github.com/thomvanoorschot/async_zocket/archive/main.tar.gz",
.hash = "...", // Update with actual hash
},
},
const std = @import("std");
const AsyncZocket = @import("async_zocket");
const xev = @import("xev");
// Initialize event loop
var loop = try xev.Loop.init(.{});
defer loop.deinit();
// Define message callback
const wrapperStruct = struct {
const Self = @This();
fn read_callback(context: *anyopaque, payload: []const u8) !void {
// You can access the context by casting it to the correct type
// const self = @as(*Self, @ptrCast(context));
// self.read_callback(self.callback_context, payload);
std.log.info("read_callback: {s}\n", .{payload});
_ = context;
}
};
var ws = wrapperStruct{};
// Create and connect client
var client = try AsyncZocket.Client.init(
std.heap.page_allocator,
&loop,
.{
.host = "127.0.0.1",
.port = 8080,
.path = "/ws",
.use_tls = true
},
wrapperStruct.read_callback,
@ptrCast(&ws)
);
try client.connect();
// Send a message
try client.write("Hello, WebSocket!");
// Run event loop
try loop.run(.until_done);
const std = @import("std");
const AsyncZocket = @import("async_zocket");
const xev = @import("xev");
// Initialize event loop
var loop = try xev.Loop.init(.{});
defer loop.deinit();
// Define callbacks
const wrapperStruct = struct {
const Self = @This();
fn accept_callback(
_: ?*anyopaque,
_: *xev.Loop,
_: *xev.Completion,
cc: *ClientConnection,
) xev.CallbackAction {
cc.read();
return .rearm;
}
fn read_callback(
context: ?*anyopaque,
payload: []const u8,
) void {
_ = context;
std.log.info("read_callback: {s}", .{payload});
std.heap.page_allocator.free(payload);
}
};
var ws = wrapperStruct{};
// Create and start server
var server = try AsyncZocket.Server.init(
std.heap.page_allocator,
&loop,
.{
.host = "127.0.0.1",
.port = 8081,
.max_connections = 10,
},
@ptrCast(&ws),
wrapperStruct.accept_callback,
wrapperStruct.read_callback,
);
server.accept();
// Run event loop
try loop.run(.until_done);
Client.init()
- Initialize a new WebSocket clientclient.connect()
- Connect to the WebSocket serverclient.write()
- Send a text messageclient.read()
- Start reading incoming messagesclient.deinit()
- Clean up client resources
Server.init()
- Initialize a new WebSocket serverserver.accept()
- Start accepting client connectionsserver.returnConnection()
- Return a closed connection to the poolserver.deinit()
- Clean up server resources
ClientConfig:
host: []const u8
- Server hostname or IP addressport: u16
- Server port numberpath: []const u8
- WebSocket endpoint pathuse_tls: bool
- Encrypts traffic
ServerOptions:
host: []const u8
- Server hostname or IP addressport: u16
- Server port numbermax_connections: u31
- Maximum concurrent connections (default: 1024)
🚀 Production Ready - The library implements a complete WebSocket solution with both client and server capabilities.
Implemented Features:
- Full WebSocket protocol (RFC 6455) compliance
- Client and server implementations
- All frame types (Text, Binary, Control frames)
- Proper masking and unmasking
- Connection management and pooling
- Asynchronous I/O with xev
- SSL/TLS support
- Zig 0.15.0-dev or later
Contributions are welcome! Please feel free to submit pull requests, report bugs, or suggest features.
This project is licensed under the MIT License - see the LICENSE file for details.