阿里云主机折上折
  • 微信号
Current Site:Index > TCP/UDP programming

TCP/UDP programming

Author:Chuan Chen 阅读数:42540人阅读 分类: Node.js

TCP Programming Basics

TCP (Transmission Control Protocol) is a connection-oriented, reliable transport protocol. Node.js provides TCP programming capabilities through the net module. Creating a TCP server requires just a few lines of code:

const net = require('net');
const server = net.createServer((socket) => {
  console.log('Client connected');
  
  socket.on('data', (data) => {
    console.log(`Received data: ${data}`);
    socket.write(`ECHO: ${data}`);
  });

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

server.listen(8124, () => {
  console.log('Server started on port 8124');
});

Implementing a TCP client is equally simple:

const net = require('net');
const client = net.connect({port: 8124}, () => {
  console.log('Connected to server');
  client.write('Hello TCP!');
});

client.on('data', (data) => {
  console.log(data.toString());
  client.end();
});

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

Handling TCP Packet Sticking

TCP is a streaming protocol, so message boundary issues need to be addressed. Common solutions include:

  1. Fixed-Length Protocol:
// Sender
const data = Buffer.alloc(4);
data.writeInt32BE(1234, 0);
socket.write(data);

// Receiver
let buffer = Buffer.alloc(0);
socket.on('data', (chunk) => {
  buffer = Buffer.concat([buffer, chunk]);
  while(buffer.length >= 4) {
    const value = buffer.readInt32BE(0);
    console.log(value);
    buffer = buffer.slice(4);
  }
});
  1. Delimiter Protocol:
// Sender
socket.write('Message content|');

// Receiver
let buffer = '';
socket.on('data', (chunk) => {
  buffer += chunk.toString();
  const messages = buffer.split('|');
  buffer = messages.pop();
  messages.forEach(msg => console.log(msg));
});

UDP Programming Implementation

UDP is implemented via the dgram module and is suitable for scenarios requiring high real-time performance:

const dgram = require('dgram');
const server = dgram.createSocket('udp4');

server.on('message', (msg, rinfo) => {
  console.log(`Server received: ${msg} from ${rinfo.address}:${rinfo.port}`);
});

server.bind(41234, () => {
  console.log('UDP server started');
});

const client = dgram.createSocket('udp4');
client.send('Hello UDP', 41234, 'localhost', (err) => {
  if (err) throw err;
  client.close();
});

Protocol Selection Considerations

TCP Use Cases:

  • Reliable transmission required (e.g., file transfer)
  • Data order must be guaranteed
  • Long-lived connections (e.g., real-time chat)

UDP Use Cases:

  • High real-time requirements (e.g., video conferencing)
  • Minor packet loss acceptable (e.g., DNS queries)
  • Broadcast/multicast applications

Advanced Application Examples

TCP Proxy Server Implementation:

const net = require('net');
const proxy = net.createServer((clientSocket) => {
  const serverSocket = net.connect(80, 'example.com');
  
  clientSocket.pipe(serverSocket);
  serverSocket.pipe(clientSocket);
  
  serverSocket.on('error', (err) => {
    console.error('Server connection error:', err);
    clientSocket.end();
  });
});

proxy.listen(8080);

UDP Multicast Example:

const dgram = require('dgram');
const socket = dgram.createSocket('udp4');

socket.on('listening', () => {
  socket.addMembership('224.0.0.114');
});

socket.on('message', (msg, rinfo) => {
  console.log(`Received multicast message: ${msg}`);
});

socket.bind(41234);

// Sending multicast
const client = dgram.createSocket('udp4');
client.send('Multicast test', 41234, '224.0.0.114');

Performance Optimization Techniques

  1. TCP Connection Pool Management:
class ConnectionPool {
  constructor(maxConnections = 10) {
    this.pool = [];
    this.max = maxConnections;
  }

  getConnection() {
    if(this.pool.length > 0) {
      return Promise.resolve(this.pool.pop());
    }
    return new Promise((resolve) => {
      const conn = net.createConnection(8124);
      conn.on('connect', () => resolve(conn));
    });
  }

  releaseConnection(conn) {
    if(this.pool.length < this.max) {
      this.pool.push(conn);
    } else {
      conn.end();
    }
  }
}
  1. UDP Batch Send Optimization:
function batchSend(socket, messages, port, address) {
  let index = 0;
  
  function sendNext() {
    if(index >= messages.length) return;
    
    socket.send(messages[index], port, address, (err) => {
      if(err) console.error('Send failed:', err);
      index++;
      setImmediate(sendNext);  // Avoid stack overflow
    });
  }
  
  sendNext();
}

Error Handling Practices

TCP Error Handling Best Practices:

server.on('error', (err) => {
  if(err.code === 'EADDRINUSE') {
    console.error('Port in use, retrying...');
    setTimeout(() => {
      server.close();
      server.listen(PORT);
    }, 1000);
  } else {
    console.error('Server error:', err);
  }
});

socket.on('error', (err) => {
  console.error('Connection error:', err);
  // Decide whether to reconnect based on error type
});

UDP Error Handling Patterns:

udpSocket.on('error', (err) => {
  console.error(`UDP error: ${err.stack}`);
  udpSocket.close();
  
  // For critical services, attempt to restart
  if(isCritical) {
    setTimeout(createUDPServer, 1000);
  }
});

Practical Application Examples

Implementing a Simple RPC Framework:

// TCP-RPC Server
class RPCServer {
  constructor(port) {
    this.methods = {};
    this.server = net.createServer(this.handleConnection.bind(this));
    this.server.listen(port);
  }

  register(name, method) {
    this.methods[name] = method;
  }

  handleConnection(socket) {
    let buffer = '';
    socket.on('data', (data) => {
      buffer += data;
      const requests = buffer.split('\n');
      buffer = requests.pop();
      
      requests.forEach(request => {
        try {
          const {id, method, params} = JSON.parse(request);
          const result = this.methods[method](...params);
          socket.write(JSON.stringify({id, result}) + '\n');
        } catch(err) {
          socket.write(JSON.stringify({error: err.message}) + '\n');
        }
      });
    });
  }
}

// Usage example
const rpc = new RPCServer(8080);
rpc.register('add', (a, b) => a + b);

UDP-Based Service Discovery:

// Service Provider
const beacon = dgram.createSocket('udp4');
setInterval(() => {
  const serviceInfo = JSON.stringify({
    name: 'my-service',
    port: 3000,
    timestamp: Date.now()
  });
  beacon.send(serviceInfo, 8888, '255.255.255.255');
}, 5000);

// Service Discoverer
const discover = dgram.createSocket('udp4');
discover.bind(8888, () => {
  discover.setBroadcast(true);
});

const services = {};
discover.on('message', (msg) => {
  const info = JSON.parse(msg);
  services[info.name] = {
    ...info,
    lastSeen: Date.now()
  };
});

// Clean up expired services
setInterval(() => {
  const now = Date.now();
  Object.keys(services).forEach(name => {
    if(now - services[name].lastSeen > 10000) {
      delete services[name];
    }
  });
}, 5000);

本站部分内容来自互联网,一切版权均归源网站或源作者所有。

如果侵犯了你的权益请来信告知我们删除。邮箱:cc@cccx.cn

上一篇:HTTPS与安全通信

下一篇:WebSocket实现

Front End Chuan

Front End Chuan, Chen Chuan's Code Teahouse 🍵, specializing in exorcising all kinds of stubborn bugs 💻. Daily serving baldness-warning-level development insights 🛠️, with a bonus of one-liners that'll make you laugh for ten years 🐟. Occasionally drops pixel-perfect romance brewed in a coffee cup ☕.