Build Custom TCP Servers with Node.js net.createServer
The net.createServer method in Node.js is a powerful,
low-level tool that allows developers to build custom TCP (Transmission
Control Protocol) servers. This article explains how the method works,
details how to handle raw data streams through socket connections, and
provides a practical implementation example to help you build your own
network applications.
Understanding the net.createServer Method
The net module is a core, built-in Node.js module that
provides an asynchronous network API for creating stream-based TCP
servers and clients. When you call net.createServer(),
Node.js initializes a new TCP server instance.
Unlike higher-level protocols like HTTP, TCP operates at the
transport layer. This means net.createServer does not parse
headers or manage request-response lifecycles automatically. Instead, it
provides a raw, bi-directional pipe between the server and the connected
client.
How the Connection Lifecycle Works
The net.createServer method accepts an optional listener
callback function that automatically executes whenever a new client
connects to the server.
const net = require('net');
const server = net.createServer((socket) => {
console.log('A client has connected.');
});The callback function receives a socket object (an
instance of net.Socket). This socket is a duplex stream,
meaning it can both read data from the client and write data back to the
client.
To start accepting connections, you must instruct the server to
listen on a specific port and host using the
server.listen() method:
server.listen(8080, '127.0.0.1', () => {
console.log('TCP server is running on port 8080');
});Handling Data and Socket Events
Because the socket object is a standard Node.js stream,
you interact with it using event listeners. The three most critical
events to handle are:
data: Emitted whenever the client sends data to the server. The data is received as a raw Buffer, which can be converted to a string using.toString().end: Emitted when the client requests to close the TCP connection.error: Emitted if a network error occurs, such as an abrupt disconnection.
Writing Data Back to the Client
To send data back to the client, you use the
socket.write() method. This sends raw data across the TCP
socket. You can also gracefully close the connection from the server
side using the socket.end() method.
A Complete TCP Echo Server Example
The following example demonstrates a functional TCP “echo” server. When a client connects and sends text, the server logs the input and writes the exact same message back to the client.
const net = require('net');
const server = net.createServer((socket) => {
socket.write('Welcome to the custom TCP server!\n');
// Handle incoming data from the client
socket.on('data', (data) => {
const message = data.toString().trim();
console.log(`Received: ${message}`);
// Echo the message back to the client
socket.write(`You said: ${message}\n`);
});
// Handle client disconnection
socket.on('end', () => {
console.log('Client disconnected.');
});
// Handle connection errors
socket.on('error', (err) => {
console.error(`Socket error: ${err.message}`);
});
});
// Bind the server to port 3000
server.listen(3000, () => {
console.log('TCP server listening on port 3000');
});You can test this server locally by running the script and using a command-line tool like Netcat or Telnet in your terminal:
nc localhost 3000Why Build Custom TCP Servers?
Using net.createServer is ideal for building highly
optimized, low-overhead network applications that do not require the
overhead of the HTTP protocol. Common use cases include:
- Custom IoT Protocols: Communicating with smart hardware devices that send lightweight binary payloads.
- Real-time Gaming Servers: Exchanging rapid, low-latency game-state data.
- Chat Applications: Creating lightweight, persistent messaging services.
- Database Proxies: Building intermediary routers or load balancers for database traffic.