const net = require('net');
// Create a server to demonstrate socket buffering
const server = net.createServer((socket) => {
console.log('Server: Client connected');
// Set highWaterMark to control buffer size
socket.setDefaultEncoding('utf8');
socket.setMaxListeners(20);
let receivedBytes = 0;
socket.on('data', (chunk) => {
receivedBytes += chunk.length;
console.log(`Server: Received ${chunk.length} bytes (total: ${receivedBytes})`);
// Demonstrate backpressure by not reading immediately
if (receivedBytes < 1000000) {
console.log('Server: Pausing socket to simulate slow processing');
socket.pause();
// Resume after a delay to demonstrate backpressure handling
setTimeout(() => {
console.log('Server: Resuming socket');
socket.resume();
}, 500);
}
});
socket.on('end', () => {
console.log(`Server: Connection ended. Total received: ${receivedBytes} bytes`);
});
socket.on('error', (err) => {
console.error('Server socket error:', err);
});
// Write a welcome message
socket.write('Welcome to the buffer demo server!\n');
});
// Start the server
const PORT = 3005;
const HOST = 'localhost';
server.listen(PORT, HOST, () => {
console.log(`Server running at ${HOST}:${PORT}`);
// Create a client to test buffering
const client = new net.Socket();
// Set highWaterMark to control buffer size
client.setDefaultEncoding('utf8');
// Track buffer status
let bufferFull = false;
let bytesWritten = 0;
const totalBytes = 2000000; // 2MB of data
const chunkSize = 100000; // 100KB chunks
client.connect(PORT, HOST, () => {
console.log('Client: Connected to server');
// Start sending data in chunks
sendChunk();
});
function sendChunk() {
if (bytesWritten >= totalBytes) {
console.log('Client: All data sent');
client.end();
return;
}
// Generate some data to send
const chunk = Buffer.alloc(Math.min(chunkSize, totalBytes - bytesWritten), 'x');
// Try to write to the socket
if (!bufferFull) {
const canWriteMore = client.write(chunk, (err) => {
if (err) {
console.error('Client write error:', err);
return;
}
console.log(`Client: Write callback for ${chunk.length} bytes`);
});
bytesWritten += chunk.length;
console.log(`Client: Wrote ${bytesWritten}/${totalBytes} bytes`);
// Check if the write buffer is full
if (!canWriteMore) {
console.log('Client: Write buffer full, waiting for drain');
bufferFull = true;
} else {
// Schedule next chunk
setImmediate(sendChunk);
}
} else {
// Buffer is full, wait for drain event
console.log('Client: Waiting for drain event before sending more');
}
}
// Handle drain event (when write buffer becomes empty)
client.on('drain', () => {
console.log('Client: Drain event - buffer is empty');
bufferFull = false;
sendChunk();
});
// Handle data from server
client.on('data', (data) => {
console.log(`Client received: ${data.toString().substring(0, 50)}...`);
});
// Handle connection close
client.on('close', () => {
console.log('Client: Connection closed');
// Close the server
server.close();
});
// Handle errors
client.on('error', (err) => {
console.error('Client error:', err);
server.close();
});
});
// Handle server errors
server.on('error', (err) => {
console.error('Server error:', err);
});
// Close server after 60 seconds if not already closed
setTimeout(() => {
if (server.listening) {
console.log('Closing server due to timeout');
server.close();
}
}, 60000);