Zig 0.16 Socket.createPair: สร้างช่องสื่อสารสองปลายสำหรับงานในโปรเซส
บางครั้งเราต้องการช่องสื่อสารสองทิศทางที่เชื่อมกันอยู่แล้วสำหรับ worker, subprocess หรือ test โดยไม่ต้องเปิดพอร์ตจริง Zig 0.16 มี std.Io.net.Socket.createPair ในโมเดล std.Io ใหม่ ช่วยขอ socket สองปลายที่คุยกันได้เหมือนโทรศัพท์ภายในครับ
WHY: ลดพิธีตั้ง listener เมื่อไม่ได้คุยข้ามเครื่อง
ถ้าเปิด listener บน loopback เราต้อง bind, หา address, listen, connect และ accept ทั้งที่โจทย์มีเพียง “ขอสอง handle ที่เชื่อมกัน” createPair รวมขั้นตอนนั้นไว้ และยังรับ Io parameter จึงไปตาม abstraction I/O ใหม่ของ Zig แทนการซ่อน global runtime
const std = @import("std");
const builtin = @import("builtin");
test "createPair returns distinct handles or the documented platform boundary" {
const io = std.testing.io;
const result = std.Io.net.Socket.createPair(io, .{});
if (result) |sockets| {
defer sockets[0].close(io);
defer sockets[1].close(io);
try std.testing.expect(sockets[0].handle != sockets[1].handle);
} else |err| switch (err) {
error.OperationUnsupported,
error.AddressFamilyUnsupported,
error.ProtocolUnsupportedBySystem,
error.ProtocolUnsupportedByAddressFamily,
error.SocketModeUnsupported,
=> try std.testing.expect(true),
// Zig 0.16.0 maps some platform socketpair refusals to Unexpected
// (macOS errno 102, Linux errno 95 / EOPNOTSUPP observed on runners).
error.Unexpected => try std.testing.expect(builtin.os.tag == .macos or builtin.os.tag == .linux),
else => return err,
}
}
ตัวอย่างตั้งใจทดสอบเพียง lifecycle ที่ไม่แตะเครือข่ายภายนอก: ถ้าระบบรองรับจะยืนยันว่าเป็นคนละ handle และปิดทั้งสองปลายด้วย defer แต่ถ้า backend ปฏิเสธ address family/mode ก็ยืนยัน portability boundary แทน บน Zig 0.16.0 ที่ทดสอบจริง ทั้ง macOS (errno 102) และ Linux (errno 95 / EOPNOTSUPP) คืนค่าที่ std จัดเป็น Unexpected จึงยอมรับเฉพาะสองแพลตฟอร์มนี้แบบเปิดเผย ไม่กลบ error เดียวกันบนระบบอื่น
ค่าเริ่มต้นของ options คือ family แบบ IPv4 และ stream mode ตาม source ของ Zig 0.16 แต่ระบบปฏิบัติการอาจไม่รองรับรูปแบบเดียวกันทั้งหมด การทดสอบรอบนี้พบ macOS คืน Unexpected จาก errno 102 จริง จึงต้องถือ API นี้เป็น platform-sensitive ในรุ่นนี้ รับ error อย่าง OperationUnsupported, quota ของ file descriptor หรือทรัพยากรระบบไม่พอ และอย่าแปลงทุก error เป็น “network ล่ม” เพราะคู่นี้อาจไม่ออก network เลย
เมื่อไรใช้ pipe หรือ queue แทน
socket pair เหมาะเมื่อ protocol เดิมคาด socket, ต้องสื่อสารสองทิศทาง หรืออยากส่ง handle ให้ subprocess ส่วน pipe เหมาะกับ byte stream ทางเดียวและ intent ชัดกว่า ถ้าทุกอย่างอยู่ในโปรเซสเดียวและไม่ต้องใช้ OS handle, queue/channel ของ runtime อาจเบาและทดสอบง่ายกว่า
Socket เป็น resource ที่ต้องปิดเอง การ copy ค่า struct ไม่ได้หมายถึง duplicate OS handle อย่างปลอดภัย จึงควรกำหนดเจ้าของแต่ละปลายชัด และอย่าปิดซ้ำจากสำเนาหลายชุด
Recap
- ใช้ createPair เมื่ออยากได้ socket สองปลายที่เชื่อมกัน
- ปิดทั้งสอง handle ด้วย defer
- จัดการ unsupported/quota errors แยกจาก network failure
- เลือก pipe หรือ in-process queue เมื่อไม่ต้องใช้ socket