阿里云主机折上折
  • 微信号
您当前的位置:网站首页 > TCP/UDP编程

TCP/UDP编程

作者:陈川 阅读数:42541人阅读 分类: Node.js

TCP编程基础

TCP(传输控制协议)是面向连接的可靠传输协议,Node.js通过net模块提供TCP编程能力。创建TCP服务器只需几行代码:

const net = require('net');
const server = net.createServer((socket) => {
  console.log('客户端已连接');
  
  socket.on('data', (data) => {
    console.log(`收到数据: ${data}`);
    socket.write(`ECHO: ${data}`);
  });

  socket.on('end', () => {
    console.log('客户端断开连接');
  });
});

server.listen(8124, () => {
  console.log('服务器启动在8124端口');
});

TCP客户端实现同样简单:

const net = require('net');
const client = net.connect({port: 8124}, () => {
  console.log('连接到服务器');
  client.write('Hello TCP!');
});

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

client.on('end', () => {
  console.log('断开服务器连接');
});

TCP粘包处理

TCP是流式协议,需要处理消息边界问题。常见解决方案:

  1. 固定长度协议
// 发送方
const data = Buffer.alloc(4);
data.writeInt32BE(1234, 0);
socket.write(data);

// 接收方
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. 分隔符协议
// 发送方
socket.write('消息内容|');

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

UDP编程实现

UDP通过dgram模块实现,适合实时性要求高的场景:

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

server.on('message', (msg, rinfo) => {
  console.log(`服务器收到: ${msg} 来自 ${rinfo.address}:${rinfo.port}`);
});

server.bind(41234, () => {
  console.log('UDP服务器启动');
});

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

协议选择考量

TCP适用场景

  • 需要可靠传输(如文件传输)
  • 需要保证数据顺序
  • 长连接通信(如实时聊天)

UDP适用场景

  • 实时性要求高(如视频会议)
  • 允许少量丢包(如DNS查询)
  • 广播/多播应用

高级应用示例

TCP代理服务器实现

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('服务器连接错误:', err);
    clientSocket.end();
  });
});

proxy.listen(8080);

UDP组播示例

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(`收到组播消息: ${msg}`);
});

socket.bind(41234);

// 发送组播
const client = dgram.createSocket('udp4');
client.send('组播测试', 41234, '224.0.0.114');

性能优化技巧

  1. TCP连接池管理
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批量发送优化
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('发送失败:', err);
      index++;
      setImmediate(sendNext);  // 避免堆栈溢出
    });
  }
  
  sendNext();
}

错误处理实践

TCP错误处理最佳实践

server.on('error', (err) => {
  if(err.code === 'EADDRINUSE') {
    console.error('端口被占用,正在重试...');
    setTimeout(() => {
      server.close();
      server.listen(PORT);
    }, 1000);
  } else {
    console.error('服务器错误:', err);
  }
});

socket.on('error', (err) => {
  console.error('连接错误:', err);
  // 根据错误类型决定是否重连
});

UDP错误处理模式

udpSocket.on('error', (err) => {
  console.error(`UDP错误: ${err.stack}`);
  udpSocket.close();
  
  // 对于关键服务应该尝试重启
  if(isCritical) {
    setTimeout(createUDPServer, 1000);
  }
});

实际应用案例

实现简单的RPC框架

// TCP-RPC服务器
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');
        }
      });
    });
  }
}

// 使用示例
const rpc = new RPCServer(8080);
rpc.register('add', (a, b) => a + b);

UDP实现服务发现

// 服务提供方
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);

// 服务发现方
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()
  };
});

// 清理过期服务
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实现

前端川

前端川,陈川的代码茶馆🍵,专治各种不服的Bug退散符💻,日常贩卖秃头警告级的开发心得🛠️,附赠一行代码笑十年的摸鱼宝典🐟,偶尔掉落咖啡杯里泡开的像素级浪漫☕。‌