JavaScript: a TCP echo server with the net module

Send a line through a TCP socket and print the server's reply.

JavaScript
const net = require("node:net");

const server = net.createServer((socket) => {
  socket.on("data", (chunk) => {
    socket.end("echo: " + chunk.toString().trim() + "\n");
  });
});

server.listen(0, "127.0.0.1", () => {
  const client = net.connect(server.address().port, "127.0.0.1", () => {
    client.write("hello\n");
  });
  client.on("data", (reply) => {
    console.log(reply.toString().trim());
  });
  client.on("close", () => server.close());
});
Output
echo: hello

Explanation

TCP gives two programs a reliable stream of bytes. The net module exposes it directly. net.createServer calls your handler for each new connection with a socket, and a socket emits a data event whenever bytes arrive and a close event when the connection ends.

The server in this example replies to the first chunk it receives and then closes its side with socket.end. The client connects, writes a line, prints what comes back, and closes the server when its own socket is closed. TCP is a stream, so one write is not guaranteed to arrive as one data event. Real protocols need delimiters or length prefixes.

Explore the dry run
Guided walkthroughReady
1const net = require("node:net");
2
3const server = net.createServer((socket) => {
4 socket.on("data", (chunk) => {
5 socket.end("echo: " + chunk.toString().trim() + "\n");
6 });
7});
8
9server.listen(0, "127.0.0.1", () => {
10 const client = net.connect(server.address().port, "127.0.0.1", () => {
11 client.write("hello\n");
12 });
13 client.on("data", (reply) => {
14 console.log(reply.toString().trim());
15 });
16 client.on("close", () => server.close());
17});

Follow the example

Start to inspect the source, values, and output. These prepared steps explain the published sample; grouped loop steps describe multiple iterations.

View the complete dry-run table
Prepared trace of the published program. Some rows group repeated iterations.
Step / lineWhat happensState after stepOutput so far
The handler runs for every incoming connection.—
—
Listen on the loopback address and any free port.—
—
The client sends a line once the connection is established.—
—
The server echoes the data back and closes its side.reply = echo: hello
—
The client prints the reply.reply = echo: hello
echo: hello

Cost and common mistakes

O(m) for an m-byte message.

  • A single data event may contain part of a message or several messages. Buffer the bytes until a delimiter arrives.
  • Not closing the server leaves the process running forever. Close it once the client is finished.
  • Data arrives as Buffers. Convert with toString() or set an encoding before treating it as text.

Try it yourself

How would you let the server handle many clients?

Reveal answer and reasoning

Nothing extra is needed: createServer calls the handler for every connection, and each socket has its own events.

Further reading