Networking

TCP

Transmission Control Protocol - A connection-oriented protocol that provides reliable, ordered, and error-checked delivery of data between applications over IP networks.

What is TCP?

TCP (Transmission Control Protocol) is a core protocol of the Internet Protocol Suite that provides reliable, ordered, and error-checked data transmission between applications. TCP sits at the Transport Layer (Layer 4) and is used by most internet applications including HTTP, HTTPS, FTP, and email.

TCP vs UDP

Key Differences

interface ProtocolComparison {
  tcp: {
    type: 'Connection-oriented';
    reliability: 'Guaranteed delivery';
    ordering: 'Packets arrive in order';
    speed: 'Slower (overhead)';
    headerSize: '20-60 bytes';
    errorChecking: 'Extensive';
    useCases: ['HTTP', 'HTTPS', 'FTP', 'Email', 'SSH'];
  };
  udp: {
    type: 'Connectionless';
    reliability: 'Best effort (no guarantee)';
    ordering: 'Packets may arrive out of order';
    speed: 'Faster (minimal overhead)';
    headerSize: '8 bytes';
    errorChecking: 'Basic checksum';
    useCases: ['DNS', 'Streaming', 'Gaming', 'VoIP', 'IoT'];
  };
}

TCP Three-Way Handshake

Connection Establishment

Client                          Server
  |                               |
  |-- SYN (seq=100) ------------>|  1. Client initiates
  |                               |
  |<- SYN-ACK (seq=300,ack=101)--|  2. Server acknowledges
  |                               |
  |-- ACK (seq=101,ack=301) ---->|  3. Client confirms
  |                               |
  |   Connection Established      |

Sequence:
1. SYN: Client sends synchronization packet
2. SYN-ACK: Server acknowledges and sends its own SYN
3. ACK: Client acknowledges server's SYN

State: ESTABLISHED

Connection Termination

Client                          Server
  |                               |
  |-- FIN (seq=500) ------------>|  1. Client wants to close
  |                               |
  |<- ACK (ack=501) -------------|  2. Server acknowledges
  |                               |
  |<- FIN (seq=700) -------------|  3. Server sends FIN
  |                               |
  |-- ACK (ack=701) ------------>|  4. Client acknowledges
  |                               |
  |   Connection Closed           |

Four-way handshake for graceful shutdown

TCP in Node.js

Creating a TCP Server

import net from 'net';

const server = net.createServer((socket) => {
  console.log('Client connected:', socket.remoteAddress);

  // Handle incoming data
  socket.on('data', (data) => {
    console.log('Received:', data.toString());

    // Echo back to client
    socket.write(`Echo: ${data.toString()}`);
  });

  // Handle client disconnect
  socket.on('end', () => {
    console.log('Client disconnected');
  });

  // Handle errors
  socket.on('error', (err) => {
    console.error('Socket error:', err.message);
  });
});

server.listen(3000, () => {
  console.log('TCP server listening on port 3000');
});

// Graceful shutdown
process.on('SIGTERM', () => {
  server.close(() => {
    console.log('Server closed');
    process.exit(0);
  });
});

Creating a TCP Client

import net from 'net';

const client = net.createConnection(
  {
    host: 'localhost',
    port: 3000
  },
  () => {
    console.log('Connected to server');

    // Send data
    client.write('Hello, server!');
  }
);

// Receive data from server
client.on('data', (data) => {
  console.log('Received:', data.toString());
  client.end(); // Close connection
});

// Handle connection end
client.on('end', () => {
  console.log('Disconnected from server');
});

// Handle errors
client.on('error', (err) => {
  console.error('Connection error:', err.message);
});

TCP with Proxies

SOCKS5 TCP Proxy

import net from 'net';

interface SOCKSConfig {
  proxyHost: string;
  proxyPort: number;
  targetHost: string;
  targetPort: number;
}

class SOCKS5Client {
  private config: SOCKSConfig;

  constructor(config: SOCKSConfig) {
    this.config = config;
  }

  async connect(): Promise<net.Socket> {
    return new Promise((resolve, reject) => {
      // Connect to SOCKS5 proxy
      const socket = net.createConnection(
        {
          host: this.config.proxyHost,
          port: this.config.proxyPort
        },
        async () => {
          try {
            // SOCKS5 handshake
            await this.handshake(socket);

            // Connect to target through proxy
            await this.connectTarget(socket);

            resolve(socket);
          } catch (error) {
            reject(error);
          }
        }
      );

      socket.on('error', reject);
    });
  }

  private async handshake(socket: net.Socket): Promise<void> {
    return new Promise((resolve, reject) => {
      // Send greeting: VER | NMETHODS | METHODS
      const greeting = Buffer.from([0x05, 0x01, 0x00]);
      socket.write(greeting);

      socket.once('data', (data) => {
        if (data[0] === 0x05 && data[1] === 0x00) {
          resolve();
        } else {
          reject(new Error('SOCKS5 handshake failed'));
        }
      });
    });
  }

  private async connectTarget(socket: net.Socket): Promise<void> {
    return new Promise((resolve, reject) => {
      // Build connection request
      const request = this.buildConnectRequest();
      socket.write(request);

      socket.once('data', (data) => {
        if (data[0] === 0x05 && data[1] === 0x00) {
          resolve();
        } else {
          reject(new Error('SOCKS5 connection failed'));
        }
      });
    });
  }

  private buildConnectRequest(): Buffer {
    const { targetHost, targetPort } = this.config;

    // VER | CMD | RSV | ATYP
    const header = Buffer.from([0x05, 0x01, 0x00, 0x03]);

    // Domain length
    const domainLength = Buffer.from([targetHost.length]);

    // Domain
    const domain = Buffer.from(targetHost);

    // Port (big-endian)
    const port = Buffer.allocUnsafe(2);
    port.writeUInt16BE(targetPort);

    return Buffer.concat([header, domainLength, domain, port]);
  }
}

// Usage
const socks5 = new SOCKS5Client({
  proxyHost: 'proxy.example.com',
  proxyPort: 1080,
  targetHost: 'api.example.com',
  targetPort: 443
});

const socket = await socks5.connect();

// Now use socket to communicate with target
socket.write('GET / HTTP/1.1\r\nHost: api.example.com\r\n\r\n');

TCP Connection Pooling

Reusable Connection Pool

class TCPConnectionPool {
  private pool: Map<string, net.Socket[]>;
  private maxConnections: number;

  constructor(maxConnections: number = 10) {
    this.pool = new Map();
    this.maxConnections = maxConnections;
  }

  async getConnection(host: string, port: number): Promise<net.Socket> {
    const key = `${host}:${port}`;
    const connections = this.pool.get(key) || [];

    // Return existing connection if available
    if (connections.length > 0) {
      const socket = connections.pop()!;

      // Verify connection is still alive
      if (!socket.destroyed) {
        return socket;
      }
    }

    // Create new connection
    return this.createConnection(host, port, key);
  }

  private createConnection(
    host: string,
    port: number,
    key: string
  ): Promise<net.Socket> {
    return new Promise((resolve, reject) => {
      const socket = net.createConnection({ host, port }, () => {
        // Enable keep-alive
        socket.setKeepAlive(true, 60000);

        resolve(socket);
      });

      socket.on('error', reject);
    });
  }

  releaseConnection(socket: net.Socket, host: string, port: number): void {
    if (socket.destroyed) return;

    const key = `${host}:${port}`;
    const connections = this.pool.get(key) || [];

    if (connections.length < this.maxConnections) {
      connections.push(socket);
      this.pool.set(key, connections);
    } else {
      // Pool is full, close connection
      socket.end();
    }
  }

  closeAll(): void {
    for (const connections of this.pool.values()) {
      connections.forEach(socket => socket.end());
    }
    this.pool.clear();
  }
}

// Usage
const pool = new TCPConnectionPool(20);

// Get connection
const socket = await pool.getConnection('api.example.com', 80);

// Use connection
socket.write('GET / HTTP/1.1\r\n\r\n');

socket.on('data', (data) => {
  console.log(data.toString());

  // Return to pool
  pool.releaseConnection(socket, 'api.example.com', 80);
});

TCP Performance Tuning

Socket Options

function optimizeTCPSocket(socket: net.Socket): void {
  // Disable Nagle's algorithm for lower latency
  socket.setNoDelay(true);

  // Enable keep-alive
  socket.setKeepAlive(true, 60000); // 60 seconds

  // Set buffer sizes
  socket.setReadableHighWaterMark(64 * 1024);  // 64KB
  socket.setWritableHighWaterMark(64 * 1024);

  // Set timeout
  socket.setTimeout(30000); // 30 seconds

  socket.on('timeout', () => {
    console.log('Socket timeout');
    socket.end();
  });
}

// Usage
const socket = net.createConnection({ host: 'example.com', port: 80 });
optimizeTCPSocket(socket);

Measuring TCP Performance

class TCPPerformanceMonitor {
  private startTime: number = 0;
  private bytesReceived: number = 0;
  private bytesSent: number = 0;

  startMonitoring(socket: net.Socket): void {
    this.startTime = Date.now();

    socket.on('data', (data) => {
      this.bytesReceived += data.length;
    });

    // Track sent data
    const originalWrite = socket.write.bind(socket);
    socket.write = ((data: any, ...args: any[]) => {
      const buffer = Buffer.isBuffer(data) ? data : Buffer.from(data);
      this.bytesSent += buffer.length;
      return originalWrite(data, ...args);
    }) as any;
  }

  getMetrics() {
    const duration = (Date.now() - this.startTime) / 1000; // seconds

    return {
      duration: `${duration.toFixed(2)}s`,
      bytesReceived: this.bytesReceived,
      bytesSent: this.bytesSent,
      downloadSpeed: `${(this.bytesReceived / duration / 1024).toFixed(2)} KB/s`,
      uploadSpeed: `${(this.bytesSent / duration / 1024).toFixed(2)} KB/s`,
      totalBandwidth: this.bytesReceived + this.bytesSent
    };
  }
}

// Usage
const monitor = new TCPPerformanceMonitor();
const socket = net.createConnection({ host: 'example.com', port: 80 });

monitor.startMonitoring(socket);

socket.on('end', () => {
  console.log('Performance metrics:', monitor.getMetrics());
});

TCP Error Handling

Robust Error Handling

class RobustTCPClient {
  private maxRetries: number = 3;
  private retryDelay: number = 1000;

  async connectWithRetry(
    host: string,
    port: number,
    attempt: number = 0
  ): Promise<net.Socket> {
    try {
      return await this.connect(host, port);
    } catch (error) {
      if (attempt >= this.maxRetries) {
        throw new Error(`Failed after ${this.maxRetries} attempts: ${error}`);
      }

      console.log(`Connection failed, retrying in ${this.retryDelay}ms...`);
      await new Promise(resolve => setTimeout(resolve, this.retryDelay));

      return this.connectWithRetry(host, port, attempt + 1);
    }
  }

  private connect(host: string, port: number): Promise<net.Socket> {
    return new Promise((resolve, reject) => {
      const socket = net.createConnection({ host, port }, () => {
        resolve(socket);
      });

      // Handle common errors
      socket.on('error', (err: NodeJS.ErrnoException) => {
        switch (err.code) {
          case 'ECONNREFUSED':
            reject(new Error('Connection refused - server not listening'));
            break;
          case 'ETIMEDOUT':
            reject(new Error('Connection timed out'));
            break;
          case 'ENOTFOUND':
            reject(new Error('Host not found'));
            break;
          case 'ENETUNREACH':
            reject(new Error('Network unreachable'));
            break;
          default:
            reject(err);
        }
      });

      socket.setTimeout(10000); // 10 second timeout
      socket.on('timeout', () => {
        socket.destroy();
        reject(new Error('Connection timeout'));
      });
    });
  }
}

// Usage
const client = new RobustTCPClient();
const socket = await client.connectWithRetry('api.example.com', 443);

TCP Security

TLS/SSL over TCP

import tls from 'tls';
import fs from 'fs';

// Create secure TCP server
const options = {
  key: fs.readFileSync('server-key.pem'),
  cert: fs.readFileSync('server-cert.pem')
};

const secureServer = tls.createServer(options, (socket) => {
  console.log('Secure connection from:', socket.remoteAddress);

  socket.on('data', (data) => {
    console.log('Encrypted data received:', data.toString());
    socket.write('Secure response');
  });
});

secureServer.listen(443, () => {
  console.log('Secure TCP server listening on port 443');
});

// Create secure TCP client
const secureSocket = tls.connect(
  {
    host: 'secure.example.com',
    port: 443,
    rejectUnauthorized: true // Verify server certificate
  },
  () => {
    console.log('Secure connection established');
    console.log('Cipher:', secureSocket.getCipher());

    secureSocket.write('Encrypted message');
  }
);

TCP Best Practices

For Developers

  1. Always implement proper error handling
  2. Use connection pooling for efficiency
  3. Set appropriate timeouts
  4. Enable keep-alive for long connections
  5. Clean up connections properly

For Performance

  1. Disable Nagle’s algorithm when needed
  2. Use appropriate buffer sizes
  3. Monitor connection metrics
  4. Implement connection reuse
  5. Handle backpressure correctly

For Reliability

  1. Implement retry logic with backoff
  2. Handle all error codes appropriately
  3. Monitor connection health
  4. Use TLS for sensitive data
  5. Implement graceful shutdown

Learn More

Create a free Account to fix CORS Errors in Production

Say goodbye to CORS errors and get back to building great web applications. It's free!

CORSPROXY Dashboard

Related Terms

More in Networking

Related guides

Back to Glossary