您现在的位置是:网站首页 > TCP/UDP编程文章详情

TCP/UDP编程

TCP编程

TCP(传输控制协议)是一种面向连接的、可靠的、基于字节流的传输层通信协议。在Node.js中,可以通过net模块实现TCP服务器和客户端的编程。

创建TCP服务器

使用net.createServer()方法可以创建一个TCP服务器:

const net = require('net');

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

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

server.listen(8080, () => {
  console.log('服务器已启动,监听端口8080');
});

创建TCP客户端

TCP客户端可以使用net.connect()方法连接服务器:

const net = require('net');

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

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

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

TCP粘包问题

TCP是面向流的协议,数据没有明确的边界,可能会发生粘包现象。解决粘包问题的常见方法:

  1. 固定长度法:每个数据包长度固定
  2. 分隔符法:使用特殊字符作为分隔符
  3. 长度前缀法:在数据前添加长度信息
// 长度前缀法示例
function encode(data) {
  const buffer = Buffer.from(data);
  const lengthBuffer = Buffer.alloc(4);
  lengthBuffer.writeUInt32BE(buffer.length);
  return Buffer.concat([lengthBuffer, buffer]);
}

function decode(buffer) {
  const length = buffer.readUInt32BE(0);
  return buffer.slice(4, 4 + length).toString();
}

UDP编程

UDP(用户数据报协议)是一种无连接的、不可靠的传输层协议。在Node.js中,可以通过dgram模块实现UDP编程。

创建UDP服务器

const dgram = require('dgram');

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

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

server.on('listening', () => {
  const address = server.address();
  console.log(`服务器监听 ${address.address}:${address.port}`);
});

server.bind(41234);

创建UDP客户端

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

const message = Buffer.from('Hello UDP Server');

client.send(message, 41234, 'localhost', (err) => {
  if (err) throw err;
  console.log('消息已发送');
});

client.on('message', (msg, rinfo) => {
  console.log(`客户端收到: ${msg} 来自 ${rinfo.address}:${rinfo.port}`);
  client.close();
});

UDP广播和多播

UDP支持广播和多播功能,可以实现一对多的通信。

// 广播示例
const broadcastServer = dgram.createSocket('udp4');
broadcastServer.bind(() => {
  broadcastServer.setBroadcast(true);
});

const broadcastMessage = Buffer.from('Broadcast Message');
broadcastServer.send(broadcastMessage, 41234, '255.255.255.255');

// 多播示例
const multicastServer = dgram.createSocket('udp4');
multicastServer.bind(41234, () => {
  multicastServer.addMembership('230.1.2.3');
});

multicastServer.on('message', (msg, rinfo) => {
  console.log(`多播消息: ${msg}`);
});

TCP与UDP比较

可靠性

TCP提供可靠的数据传输,确保数据按序到达且不丢失。UDP不保证可靠性,数据可能丢失或乱序。

连接方式

TCP是面向连接的协议,需要三次握手建立连接。UDP是无连接的,直接发送数据。

性能

UDP开销小,传输效率高,适合实时性要求高的场景。TCP需要维护连接状态,开销较大。

使用场景

TCP适合需要可靠传输的场景,如文件传输、网页浏览等。UDP适合实时性要求高的场景,如视频会议、在线游戏等。

实际应用示例

实现一个简单的聊天室

// TCP聊天室服务器
const net = require('net');
const clients = [];

const chatServer = net.createServer((socket) => {
  clients.push(socket);
  socket.write('欢迎加入聊天室!\n');

  socket.on('data', (data) => {
    clients.forEach(client => {
      if (client !== socket) {
        client.write(data);
      }
    });
  });

  socket.on('end', () => {
    const index = clients.indexOf(socket);
    if (index !== -1) clients.splice(index, 1);
  });
});

chatServer.listen(3000);

实现一个简单的DNS查询工具

const dgram = require('dgram');
const dnsPacket = require('dns-packet');

const dnsClient = dgram.createSocket('udp4');

function queryDNS(domain, callback) {
  const buf = dnsPacket.encode({
    type: 'query',
    id: Math.floor(Math.random() * 65535),
    questions: [{
      type: 'A',
      name: domain
    }]
  });

  dnsClient.send(buf, 0, buf.length, 53, '8.8.8.8', (err) => {
    if (err) return callback(err);
  });

  dnsClient.once('message', (msg) => {
    const response = dnsPacket.decode(msg);
    callback(null, response.answers);
  });
}

queryDNS('example.com', (err, answers) => {
  if (err) throw err;
  console.log(answers);
});

性能优化技巧

TCP优化

  1. 使用Nagle算法控制小数据包发送
  2. 调整缓冲区大小
  3. 使用连接池管理TCP连接
// 调整TCP缓冲区大小
const server = net.createServer();
server.on('connection', (socket) => {
  socket.setNoDelay(true); // 禁用Nagle算法
  socket.setKeepAlive(true, 60000); // 启用keep-alive
});

UDP优化

  1. 合理设置缓冲区大小
  2. 使用多线程处理UDP数据
  3. 实现简单的重传机制提高可靠性
const udpServer = dgram.createSocket('udp4');
udpServer.bind(41234, () => {
  udpServer.setRecvBufferSize(1024 * 1024); // 设置接收缓冲区大小
  udpServer.setSendBufferSize(1024 * 1024); // 设置发送缓冲区大小
});

错误处理与调试

TCP错误处理

const tcpServer = net.createServer();

tcpServer.on('error', (err) => {
  console.error('服务器错误:', err);
});

const client = net.connect({port: 8080});
client.on('error', (err) => {
  console.error('客户端错误:', err);
});

UDP错误处理

const udpSocket = dgram.createSocket('udp4');

udpSocket.on('error', (err) => {
  console.error('UDP错误:', err);
  udpSocket.close();
});

调试技巧

  1. 使用Wireshark抓包分析
  2. 记录详细的日志
  3. 实现心跳机制检测连接状态
// TCP心跳示例
function setupHeartbeat(socket) {
  let heartbeatTimer;
  
  function resetTimer() {
    clearTimeout(heartbeatTimer);
    heartbeatTimer = setTimeout(() => {
      socket.end();
    }, 30000);
  }

  socket.on('data', (data) => {
    if (data.toString() === 'HEARTBEAT') {
      socket.write('HEARTBEAT_ACK');
    }
    resetTimer();
  });

  resetTimer();
}

安全考虑

TCP安全

  1. 使用TLS加密通信
  2. 实现认证机制
  3. 防止DDoS攻击
const tls = require('tls');
const fs = require('fs');

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

const secureServer = tls.createServer(options, (socket) => {
  // 安全通信处理
});

UDP安全

  1. 实现数据验证
  2. 防止IP欺骗
  3. 限制数据包大小
const udpServer = dgram.createSocket('udp4');

udpServer.on('message', (msg, rinfo) => {
  if (msg.length > 1024) {
    console.log('数据包过大,丢弃');
    return;
  }
  // 处理消息
});

高级应用

实现一个简单的HTTP服务器

const net = require('net');

const httpServer = net.createServer((socket) => {
  socket.on('data', (data) => {
    const request = data.toString();
    const response = `HTTP/1.1 200 OK\r\n
Content-Type: text/plain\r\n
Content-Length: 12\r\n
\r\n
Hello World!`;
    socket.write(response);
  });
});

httpServer.listen(80);

实现一个简单的RPC框架

// RPC服务器
const net = require('net');
const methods = {
  add: (a, b) => a + b,
  subtract: (a, b) => a - b
};

const rpcServer = net.createServer((socket) => {
  socket.on('data', (data) => {
    const request = JSON.parse(data);
    const result = methods[request.method](...request.params);
    socket.write(JSON.stringify({id: request.id, result}));
  });
});

rpcServer.listen(4000);

// RPC客户端
function rpcCall(method, params, callback) {
  const client = net.connect({port: 4000}, () => {
    const request = {id: Date.now(), method, params};
    client.write(JSON.stringify(request));
  });

  client.on('data', (data) => {
    const response = JSON.parse(data);
    callback(null, response.result);
    client.end();
  });
}

rpcCall('add', [1, 2], (err, result) => {
  console.log('1 + 2 =', result);
});

我的名片

网名:~川~

岗位:console.log 调试员

坐标:重庆市-九龙坡区

邮箱:cc@qdcc.cn

沙漏人生

站点信息

  • 建站时间:2013/03/16
  • 本站运行
  • 文章数量
  • 总访问量
微信公众号
每次关注
都是向财富自由迈进的一步