Servidor TCP en Node.js que recibe tramas de datos de twins (gemelos digitales), se autentica automáticamente con una API, y envía los datos a un endpoint HTTP POST.
- Servidor TCP que escucha conexiones entrantes
- Autenticación automática con la API (login y gestión de tokens)
- Cache inteligente de tokens con renovación automática
- Procesamiento y validación de tramas JSON con datos de twins
- Envío automático de datos a endpoint /v2/lectures/twin
- Respuestas estandarizadas: status: 0para éxito,status: 1para error
- Manejo robusto de errores con retry automático en caso de token expirado
- Logs detallados para debugging
- Cliente de prueba incluido
servidor-tcp/
├── index.js           # Servidor TCP principal
├── httpClient.js      # Cliente HTTP con autenticación
├── test-client.js     # Cliente de prueba
├── package.json       # Dependencias
├── .env.example       # Ejemplo de configuración
└── README.md          # Este archivo
- Node.js v14 o superior
- npm o yarn
- Instala las dependencias:
npm install- Copia el archivo de configuración:
cp .env.example .env- Edita el archivo .envcon tu configuración:
# Configuración del Servidor TCP
TCP_PORT=8080
TCP_HOST=0.0.0.0
# Configuración de la API
API_BASE_URL=https://tu-api.com
HTTP_TIMEOUT=5000
# Credenciales de autenticación
LOGIN_EMAIL=tu@email.com
LOGIN_PASSWORD=tu_passwordnpm startEl servidor comenzará a escuchar en el puerto configurado (por defecto 8080).
npm run devEl servidor espera recibir un JSON con la siguiente estructura exacta (como viene del hardware):
{
  "idTwin": 205,
  "sensors": [
    {
      "idSensor": 3,
      "idLectureType": 1,
      "value": "21.22"
    },
    {
      "idSensor": 4,
      "idLectureType": 2,
      "value": "76.02"
    }
  ],
  "unixTime": 1761350213,
  "idWarehouse": 24
}- idTwin(number): ID del twin
- sensors(array): Array de sensores, cada uno con:- idSensor(number): ID del sensor
- idLectureType(number): Tipo de lectura
- value(string): Valor de la lectura
 
- unixTime(number): Timestamp Unix en segundos
- idWarehouse(number): ID del almacén
- Al primer request, el servidor hace login automáticamente a /settings/loginUser
- Obtiene el tokenAuthde la respuesta
- Guarda el token en cache por 23 horas
- Usa el token para todas las peticiones a /v2/lectures/twin
- Si el token expira o es inválido (HTTP 401), automáticamente:
- Hace login nuevamente
- Obtiene un nuevo token
- Reintenta la petición original
 
# En una terminal, inicia el servidor
npm start
# En otra terminal, ejecuta el cliente de prueba
npm run test-clientEl cliente de prueba enviará datos de ejemplo de un twin y mostrará la respuesta.
npm run test-client '{"idTwin":205,"sensors":[{"idSensor":3,"idLectureType":1,"value":"21.22"}],"unixTime":1761350213,"idWarehouse":24}'telnet localhost 8080Luego escribe tu JSON:
{"idTwin":205,"sensors":[{"idSensor":3,"idLectureType":1,"value":"21.22"}],"unixTime":1761350213,"idWarehouse":24}echo '{"idTwin":205,"sensors":[{"idSensor":3,"idLectureType":1,"value":"21.22"}],"unixTime":1761350213,"idWarehouse":24}' | nc localhost 8080const net = require('net');
const client = net.createConnection({ port: 8080, host: 'localhost' }, () => {
  const twinData = {
    idTwin: 205,
    sensors: [
      {
        idSensor: 3,
        idLectureType: 1,
        value: "21.22"
      },
      {
        idSensor: 4,
        idLectureType: 2,
        value: "76.02"
      }
    ],
    unixTime: Math.floor(Date.now() / 1000), // Timestamp Unix en segundos
    idWarehouse: 24
  };
  client.write(JSON.stringify(twinData));
});
client.on('data', (data) => {
  console.log('Respuesta:', data.toString());
  client.end();
});El servidor responde con un JSON:
{
  "status": 0,
  "message": "OK",
  "detail": "Datos procesados y enviados correctamente",
  "timestamp": "2025-01-27T10:30:00.000Z"
}{
  "status": 1,
  "message": "ERROR",
  "detail": "Campos requeridos faltantes: unixTime",
  "timestamp": "2025-01-27T10:30:00.000Z"
}El servidor valida estrictamente:
- JSON válido
- Presencia de campos requeridos: idTwin,sensors,unixTime,idWarehouse
- sensorsdebe ser un array
- Cada sensor debe tener: idSensor,idLectureType,value
- Tipos de datos correctos:
- idTwin: number
- unixTime: number (timestamp Unix en segundos)
- idWarehouse: number
- idSensor: number
- idLectureType: number
- value: string
 
Si alguna validación falla, responde con status: 1 y un mensaje descriptivo del error.
- Cliente TCP se conecta al servidor
- Cliente envía trama JSON con datos del twin
- Servidor valida el formato y los datos
- Servidor verifica si tiene un token válido:
- Si no tiene o está expirado: hace login
- Si tiene: lo usa directamente
 
- Servidor envía datos a POST /v2/lectures/twincon el token
- Si el endpoint responde con 401:
- Renueva el token
- Reintenta la petición
 
- Servidor responde al cliente TCP:
- status: 0si todo fue exitoso
- status: 1si hubo algún error
 
El servidor genera logs detallados:
- [INFO]- Información general (conexiones, tramas recibidas)
- [SUCCESS]- Operaciones exitosas
- [ERROR]- Errores
- [AUTH]- Operaciones de autenticación
- [HTTP]- Peticiones HTTP
Ejemplo de logs:
==================================================
[INFO] Servidor TCP iniciado
[INFO] Escuchando en 0.0.0.0:8080
==================================================
[INFO] Cliente conectado: ::ffff:127.0.0.1:52341
[INFO] Datos recibidos de ::ffff:127.0.0.1:52341
[INFO] Trama recibida: {"idTwin":123,"sensors":[...],"unixTime":1738034192,"idWarehouse":24}
[INFO] Trama validada correctamente
[INFO] Twin ID: 123
[INFO] Warehouse ID: 24
[INFO] Sensores: 3
[INFO] Enviando datos del twin al endpoint HTTP...
[AUTH] Token no disponible o expirado, obteniendo nuevo token...
[AUTH] Iniciando autenticación...
[AUTH] Autenticación exitosa
[AUTH] Usuario: Hardware
[AUTH] ID Usuario: 4
[AUTH] Token válido hasta: 2025-01-28T09:30:00.000Z
[HTTP] Enviando a: https://api.ejemplo.com/v2/lectures/twin
[HTTP] Respuesta exitosa: 200
[SUCCESS] Datos del twin enviados correctamente
[INFO] Cliente desconectado: ::ffff:127.0.0.1:52341
# Instala PM2 globalmente
npm install -g pm2
# Inicia el servidor
pm2 start index.js --name servidor-tcp
# Configura para que inicie automáticamente
pm2 startup
pm2 save
# Ver logs en tiempo real
pm2 logs servidor-tcp
# Ver estado
pm2 status
# Reiniciar
pm2 restart servidor-tcp
# Detener
pm2 stop servidor-tcpCrea un archivo /etc/systemd/system/servidor-tcp.service:
[Unit]
Description=Servidor TCP con Forward HTTP
After=network.target
[Service]
Type=simple
User=tu-usuario
WorkingDirectory=/ruta/a/servidor-tcp
ExecStart=/usr/bin/node index.js
Restart=always
Environment=NODE_ENV=production
[Install]
WantedBy=multi-user.targetLuego:
sudo systemctl daemon-reload
sudo systemctl enable servidor-tcp
sudo systemctl start servidor-tcp
sudo systemctl status servidor-tcp
# Ver logs
sudo journalctl -u servidor-tcp -fCrea un Dockerfile:
FROM node:18-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
COPY . .
EXPOSE 8080
CMD ["node", "index.js"]Construye y ejecuta:
docker build -t servidor-tcp .
docker run -d -p 8080:8080 --env-file .env --name servidor-tcp --restart unless-stopped servidor-tcp
# Ver logs
docker logs -f servidor-tcpSi usas firewall en Linux, abre el puerto:
# UFW
sudo ufw allow 8080/tcp
# iptables
sudo iptables -A INPUT -p tcp --dport 8080 -j ACCEPT
sudo iptables-save > /etc/iptables/rules.v4- Verifica que el puerto no esté en uso: lsof -i :8080
- Verifica los permisos del archivo
- Revisa los logs del servidor
- Verifica que TCP_HOST=0.0.0.0en.env
- Revisa la configuración del firewall
- Verifica que el servidor esté escuchando: netstat -tulpn | grep 8080
- Verifica que tu trama JSON contenga todos los campos requeridos: idTwin,sensors,unixTime,idWarehouse
- Verifica que cada sensor tenga: idSensor,idLectureType,value
- Verifica que LOGIN_EMAILyLOGIN_PASSWORDsean correctos en.env
- Verifica que la URL base de la API sea correcta
- Prueba las credenciales manualmente con curl:
curl -X POST https://tu-api.com/settings/loginUser \
  -H "Content-Type: application/json" \
  -d '{"email": "tu@email.com", "password": "tu_password"}'- El servidor intenta renovar automáticamente el token
- Si persiste, verifica que las credenciales sigan siendo válidas
- Revisa que el endpoint de login no haya cambiado
- Verifica que API_BASE_URLsea correcto en.env
- Verifica la conectividad con la API
- Aumenta el timeout en .env:HTTP_TIMEOUT=10000
- NUNCA subas el archivo .enval repositorio
- Usa contraseñas seguras y cámbialas regularmente
- El token se renueva automáticamente cada 23 horas
- En producción, considera usar variables de entorno del sistema en lugar de .env
- Implementa rate limiting si es necesario para prevenir abuso
- Valida y sanitiza todas las entradas
ISC