The net module provides an asynchronous network API for creating TCP servers and clients. Here's how to use it.
Basic TCP Server#
1import net from 'node:net';
2
3const server = net.createServer((socket) => {
4 console.log('Client connected');
5
6 socket.on('data', (data) => {
7 console.log('Received:', data.toString());
8 socket.write('Echo: ' + data);
9 });
10
11 socket.on('end', () => {
12 console.log('Client disconnected');
13 });
14
15 socket.on('error', (err) => {
16 console.error('Socket error:', err.message);
17 });
18});
19
20server.listen(3000, () => {
21 console.log('Server listening on port 3000');
22});Basic TCP Client#
1import net from 'node:net';
2
3const client = net.createConnection({ port: 3000 }, () => {
4 console.log('Connected to server');
5 client.write('Hello, server!');
6});
7
8client.on('data', (data) => {
9 console.log('Received:', data.toString());
10 client.end();
11});
12
13client.on('end', () => {
14 console.log('Disconnected from server');
15});
16
17client.on('error', (err) => {
18 console.error('Connection error:', err.message);
19});Server with Multiple Clients#
1import net from 'node:net';
2
3const clients = new Set();
4
5const server = net.createServer((socket) => {
6 clients.add(socket);
7 console.log(`Clients connected: ${clients.size}`);
8
9 // Send welcome message
10 socket.write('Welcome to the server!\n');
11
12 socket.on('data', (data) => {
13 const message = data.toString().trim();
14
15 // Broadcast to all clients
16 for (const client of clients) {
17 if (client !== socket && !client.destroyed) {
18 client.write(`[${socket.remoteAddress}]: ${message}\n`);
19 }
20 }
21 });
22
23 socket.on('close', () => {
24 clients.delete(socket);
25 console.log(`Clients connected: ${clients.size}`);
26 });
27
28 socket.on('error', (err) => {
29 console.error('Socket error:', err.message);
30 clients.delete(socket);
31 });
32});
33
34server.listen(3000, '0.0.0.0', () => {
35 console.log('Chat server running on port 3000');
36});Connection Options#
1import net from 'node:net';
2
3// Server options
4const serverOptions = {
5 allowHalfOpen: false, // Auto-end when client ends
6 pauseOnConnect: false, // Don't pause socket initially
7 noDelay: true, // Disable Nagle's algorithm
8 keepAlive: true, // Enable keep-alive
9 keepAliveInitialDelay: 1000,
10};
11
12const server = net.createServer(serverOptions, (socket) => {
13 // Configure socket
14 socket.setNoDelay(true);
15 socket.setKeepAlive(true, 60000);
16 socket.setTimeout(30000);
17
18 socket.on('timeout', () => {
19 console.log('Socket timeout');
20 socket.end('Connection timeout\n');
21 });
22});
23
24// Client options
25const clientOptions = {
26 port: 3000,
27 host: 'localhost',
28 family: 4, // IPv4
29 localAddress: '0.0.0.0',
30 timeout: 5000,
31};
32
33const client = net.createConnection(clientOptions);Unix Domain Sockets#
1import net from 'node:net';
2import fs from 'node:fs';
3
4const SOCKET_PATH = '/tmp/app.sock';
5
6// Remove existing socket file
7if (fs.existsSync(SOCKET_PATH)) {
8 fs.unlinkSync(SOCKET_PATH);
9}
10
11// Server on Unix socket
12const server = net.createServer((socket) => {
13 socket.on('data', (data) => {
14 console.log('Received:', data.toString());
15 socket.write('Response from server');
16 });
17});
18
19server.listen(SOCKET_PATH, () => {
20 console.log('Server listening on', SOCKET_PATH);
21});
22
23// Client connecting to Unix socket
24const client = net.createConnection({ path: SOCKET_PATH }, () => {
25 client.write('Hello via Unix socket');
26});
27
28client.on('data', (data) => {
29 console.log('Client received:', data.toString());
30 client.end();
31});Message Protocol#
1import net from 'node:net';
2
3// Length-prefixed message protocol
4class MessageProtocol {
5 constructor(socket) {
6 this.socket = socket;
7 this.buffer = Buffer.alloc(0);
8 }
9
10 send(message) {
11 const data = Buffer.from(JSON.stringify(message));
12 const length = Buffer.alloc(4);
13 length.writeUInt32BE(data.length);
14 this.socket.write(Buffer.concat([length, data]));
15 }
16
17 onData(callback) {
18 this.socket.on('data', (chunk) => {
19 this.buffer = Buffer.concat([this.buffer, chunk]);
20
21 while (this.buffer.length >= 4) {
22 const length = this.buffer.readUInt32BE(0);
23
24 if (this.buffer.length >= 4 + length) {
25 const data = this.buffer.subarray(4, 4 + length);
26 this.buffer = this.buffer.subarray(4 + length);
27
28 try {
29 const message = JSON.parse(data.toString());
30 callback(message);
31 } catch (err) {
32 console.error('Parse error:', err.message);
33 }
34 } else {
35 break;
36 }
37 }
38 });
39 }
40}
41
42// Usage
43const server = net.createServer((socket) => {
44 const protocol = new MessageProtocol(socket);
45
46 protocol.onData((message) => {
47 console.log('Received message:', message);
48 protocol.send({ status: 'ok', echo: message });
49 });
50});Connection Pool#
1import net from 'node:net';
2
3class ConnectionPool {
4 constructor(options, poolSize = 5) {
5 this.options = options;
6 this.poolSize = poolSize;
7 this.available = [];
8 this.pending = [];
9 }
10
11 async getConnection() {
12 if (this.available.length > 0) {
13 return this.available.pop();
14 }
15
16 if (this.available.length + this.pending.length < this.poolSize) {
17 return this.createConnection();
18 }
19
20 // Wait for available connection
21 return new Promise((resolve) => {
22 this.pending.push(resolve);
23 });
24 }
25
26 createConnection() {
27 return new Promise((resolve, reject) => {
28 const socket = net.createConnection(this.options, () => {
29 resolve(socket);
30 });
31
32 socket.on('error', reject);
33 });
34 }
35
36 release(socket) {
37 if (socket.destroyed) {
38 return;
39 }
40
41 if (this.pending.length > 0) {
42 const resolve = this.pending.shift();
43 resolve(socket);
44 } else {
45 this.available.push(socket);
46 }
47 }
48
49 async execute(operation) {
50 const socket = await this.getConnection();
51 try {
52 return await operation(socket);
53 } finally {
54 this.release(socket);
55 }
56 }
57
58 close() {
59 for (const socket of this.available) {
60 socket.end();
61 }
62 this.available = [];
63 }
64}
65
66// Usage
67const pool = new ConnectionPool({ port: 3000 });
68
69await pool.execute(async (socket) => {
70 socket.write('Request');
71 return new Promise((resolve) => {
72 socket.once('data', (data) => resolve(data.toString()));
73 });
74});Graceful Shutdown#
1import net from 'node:net';
2
3const clients = new Set();
4let isShuttingDown = false;
5
6const server = net.createServer((socket) => {
7 if (isShuttingDown) {
8 socket.end('Server shutting down\n');
9 return;
10 }
11
12 clients.add(socket);
13
14 socket.on('close', () => {
15 clients.delete(socket);
16 });
17
18 socket.on('data', (data) => {
19 // Handle data
20 });
21});
22
23function shutdown() {
24 console.log('Shutting down...');
25 isShuttingDown = true;
26
27 // Stop accepting new connections
28 server.close(() => {
29 console.log('Server closed');
30 });
31
32 // Close existing connections
33 for (const socket of clients) {
34 socket.end('Server shutting down\n');
35 }
36
37 // Force close after timeout
38 setTimeout(() => {
39 for (const socket of clients) {
40 socket.destroy();
41 }
42 process.exit(0);
43 }, 5000);
44}
45
46process.on('SIGTERM', shutdown);
47process.on('SIGINT', shutdown);
48
49server.listen(3000);TLS/SSL Wrapper#
1import net from 'node:net';
2import tls from 'node:tls';
3import fs from 'node:fs';
4
5// TLS Server
6const tlsOptions = {
7 key: fs.readFileSync('server-key.pem'),
8 cert: fs.readFileSync('server-cert.pem'),
9};
10
11const tlsServer = tls.createServer(tlsOptions, (socket) => {
12 console.log('Secure connection established');
13 socket.write('Welcome to secure server\n');
14
15 socket.on('data', (data) => {
16 console.log('Received:', data.toString());
17 });
18});
19
20tlsServer.listen(3443);
21
22// TLS Client
23const tlsClient = tls.connect({
24 port: 3443,
25 host: 'localhost',
26 rejectUnauthorized: false, // For self-signed certs
27}, () => {
28 console.log('Connected securely');
29 tlsClient.write('Hello secure server');
30});
31
32tlsClient.on('data', (data) => {
33 console.log('Received:', data.toString());
34});Proxy Server#
1import net from 'node:net';
2
3const proxy = net.createServer((clientSocket) => {
4 console.log('Client connected to proxy');
5
6 const serverSocket = net.createConnection({
7 port: 80,
8 host: 'example.com',
9 });
10
11 // Pipe data both ways
12 clientSocket.pipe(serverSocket);
13 serverSocket.pipe(clientSocket);
14
15 clientSocket.on('error', (err) => {
16 console.error('Client error:', err.message);
17 serverSocket.destroy();
18 });
19
20 serverSocket.on('error', (err) => {
21 console.error('Server error:', err.message);
22 clientSocket.destroy();
23 });
24
25 clientSocket.on('close', () => {
26 serverSocket.destroy();
27 });
28
29 serverSocket.on('close', () => {
30 clientSocket.destroy();
31 });
32});
33
34proxy.listen(8080, () => {
35 console.log('Proxy server on port 8080');
36});Server Events#
1import net from 'node:net';
2
3const server = net.createServer();
4
5server.on('connection', (socket) => {
6 console.log('New connection from', socket.remoteAddress);
7});
8
9server.on('listening', () => {
10 const addr = server.address();
11 console.log(`Server listening on ${addr.address}:${addr.port}`);
12});
13
14server.on('close', () => {
15 console.log('Server closed');
16});
17
18server.on('error', (err) => {
19 if (err.code === 'EADDRINUSE') {
20 console.error('Port already in use');
21 setTimeout(() => {
22 server.close();
23 server.listen(3001);
24 }, 1000);
25 } else {
26 throw err;
27 }
28});
29
30server.listen(3000);
31
32// Get server info
33console.log('Max connections:', server.maxConnections);
34console.log('Connections:', server.getConnections((err, count) => {
35 console.log('Active connections:', count);
36}));Socket Properties#
1import net from 'node:net';
2
3net.createServer((socket) => {
4 // Connection info
5 console.log('Remote address:', socket.remoteAddress);
6 console.log('Remote port:', socket.remotePort);
7 console.log('Remote family:', socket.remoteFamily);
8 console.log('Local address:', socket.localAddress);
9 console.log('Local port:', socket.localPort);
10
11 // Socket state
12 console.log('Ready state:', socket.readyState);
13 console.log('Bytes read:', socket.bytesRead);
14 console.log('Bytes written:', socket.bytesWritten);
15
16 // Check connectivity
17 if (!socket.destroyed) {
18 socket.write('Connected\n');
19 }
20}).listen(3000);Best Practices#
Connection Handling:
✓ Set timeouts
✓ Handle errors
✓ Clean up on close
✓ Use keep-alive
Message Protocol:
✓ Length-prefix messages
✓ Handle partial reads
✓ Validate input
✓ Use buffers efficiently
Performance:
✓ Disable Nagle when needed
✓ Use connection pools
✓ Limit connections
✓ Monitor memory
Avoid:
✗ Ignoring errors
✗ Memory leaks
✗ Unbounded buffers
✗ Missing timeouts
Conclusion#
The Node.js net module provides low-level TCP networking capabilities. Use net.createServer() for servers and net.createConnection() for clients. Handle data events carefully with proper buffering, implement message protocols for reliable communication, and always handle errors and cleanup. For secure connections, use the tls module with the same API patterns.