Reactor vs Proactor: Readiness vs Completion Driven I/O
Reactor Pattern
Reactor demultiplexes events and dispatches to handlers when resources become ready. The event loop calls epoll_wait (Linux) or kqueue (BSD). When a socket is readable, the reactor calls your handler. You then perform the actual I/O operation synchronously.
Readiness notification means the kernel tells you a socket is ready. You must then call read() yourself. If you read less than available, you must track state and read more later. Partial reads and writes require careful buffering.
Proactor Pattern
Proactor initiates async I/O operations and dispatches handlers when operations complete. You call aio_read() with a buffer. The kernel performs the read and signals when done. Your handler receives completed data, not a readiness notification.
Completion notification means the kernel tells you the operation finished. Data is already in your buffer. No partial reads to handle at the application level. But buffer management is trickier: you must pre-allocate buffers for operations in flight.
Platform Support
Linux: epoll is reactor style. io_uring (kernel 5.1+) supports proactor style with true async I/O. Traditional aio is limited and rarely used.
Windows: IOCP (I/O Completion Ports) is proactor style. It notifies on completion, not readiness. High performance Windows servers use IOCP exclusively.
BSD and macOS: kqueue is reactor style but can emulate some proactor behaviors. Most code uses reactor pattern.