Event-driven TCP with net.createServer

Four lines of substance. createServer takes a connection callback. The data event fires whenever bytes arrive. The event loop handles concurrency.

01-tcp-echo/server.mjs
javascript
import { createServer } from "node:net";

const server = createServer((conn) => {
  console.log(`  [conn] ${conn.remoteAddress}:${conn.remotePort} connected`);

  conn.on("data", (chunk) => {
    conn.write(chunk);
  });

  conn.on("end", () => console.log(`  [conn] disconnected`));
  conn.on("error", (err) => console.log(`  [err] ${err.message}`));
});

server.listen(6380, "127.0.0.1", () => {
  console.log(`echo server listening on 127.0.0.1:6380`);
});

The entire echo server. Every conn gets its own callback context, but they all run on the same thread.

libuv. It wraps the OS event notification mechanism (epoll on Linux, kqueue on macOS, IOCP on Windows). When a socket has data, libuv fires the JavaScript callback. While JS is running, IO events queue. When JS yields, libuv drains the queue. This is what lets one thread serve thousands of connections.

Quiz: Quiz

Loading practice…