La comunicación con la Pagando Check Pad² requiere que el cliente desarrolle una aplicación o servicio. Esta aplicación funge como el punto de control para la realización de operaciones. Todo a través de una interfaz TCP/IP, estableciendo la conectividad mediante el dispositivo controlador. En la topología de red compartida por switch, el dispositivo controlador (PC) y la terminal están conectados a la misma red local (LAN) a través de un switch. El router de la red actúa como gateway y le asigna su propia IP tanto a la PC como a la terminal. Esto determina cómo se determina y configura la IP de escucha del Bridge (Paso 1); el resto del flujo de conexión (puerto de escucha, aceptación del cliente, hilo dedicado, y el mantenimiento de la conexión ya establecida) sigue el mismo patrón cliente-servidor.
Rol de la aplicación o servicio (Bridge)
Estas serán las funciones básicas que deberá realizar el Bridge:
- Realizar una conexión TCP/IP en un puerto específico (
49154). - Escuchar en la interfaz de red correcta dentro de la LAN compartida por el switch.
- Capacidad de generar y enviar mensajes en formato JSON.
- Capacidad de recibir e interpretar mensajes en formato JSON.
- Mantener la conexión activa mediante el envío periódico de heartbeat una vez que la terminal se conectó (ver Paso 6).
Pasos para la generación del Bridge
A continuación se enuncian los pasos básicos para la generación de un bridge que logre la conexión con la Pagando Check Pad² en una red compartida por switch. Los ejemplos de código son demostrativos y solo sirven de ayuda para demostrar el propósito de la función; el cliente puede realizar la selección de cualquier lenguaje de programación que esté acostumbrado a usar.
Paso 1: Configuración de IP
La aplicación o servicio necesitará una dirección de red para realizar las operaciones.
En una red compartida por switch no existe un gateway derivado de la PC: el router de la red es el gateway y le asigna su propia IP a cada equipo. Por esto, en esta topología se recomienda que el Bridge escuche en todas las interfaces de red disponibles (0.0.0.0) en vez de intentar inferir o fijar una sola IP, dejando que sea el instalador quien confirme la IP real de la PC dentro de la LAN (fija o reservada por DHCP) para capturarla del lado de la terminal.
Actualmente para la conexión se requiere tener habilitado el puerto 49154 en el cuál se realiza la conexión.
Ejemplo de conexión:
int port = 49154;
String ipv4Address = "0.0.0.0"; // Escucha en todas las interfaces de la LAN
public void init(int port, String ipv4Address) {
this.port = port;
this.ipv4Address = ipv4Address;
this.init2();
}
private void init2() {
try {
// Se valida y resuelve la dirección de escucha
this.bindAddress = InetAddress.getByName(this.ipv4Address);
} catch (Exception e) {
// Manejo de error de formato de IP
}
}
Pseudocódigo:
DEFINIR puerto COMO ENTERO = 49154
DEFINIR direccionIpv4 COMO CADENA = "0.0.0.0" // todas las interfaces de la LAN
DEFINIR direccionEscucha COMO DIRECCION
// -- PROCEDIMIENTO DE INICIALIZACIÓN --
PROCEDIMIENTO publico Inicializar(puerto, direccionIpv4)
ESTE.puerto = puerto
ESTE.direccionIpv4 = direccionIpv4
// Se llama al procedimiento privado de resolución de la dirección
ESTE.InicializarDireccion()
FIN PROCEDIMIENTO
// -- PROCEDIMIENTO PRIVADO --
PROCEDIMIENTO privado InicializarDireccion()
// Se intenta resolver la dirección de escucha
INTENTAR
// Se valida el formato de la IP y
// se guarda como dirección de escucha
ESTE.direccionEscucha = RESOLVER(ESTE.direccionIpv4)
CAPTURAR EXCEPCION
// Por ejemplo, formato de IP inválido
FIN INTENTAR
FIN PROCEDIMIENTO
Paso 2: Creación del Punto de Escucha
Dentro de la aplicación o servicio se deberá de generar un socket de conexión que permita la apertura del puerto definido anteriormente con la dirección de escucha (0.0.0.0). Así mismo, deberá de mantener una escucha activa.
serverSocket = new ServerSocket();
serverSocket.bind(new InetSocketAddress(this.bindAddress, this.port));
serverSocket.listen();
Pseudocódigo:
DEFINIR socketServidor
socketServidor = CREAR_SOCKET_SERVIDOR()
ENLAZAR socketServidor A (ESTE.direccionEscucha, ESTE.puerto)
ESCUCHAR socketServidor
Paso 3: Mantener hilo en segundo plano
Para evitar que los procesos impidan un uso de la aplicación mientras se realice esta conexión, se recomienda pasar a una conexión en segundo plano la escucha del socket de conexión.
new Thread(() -> {
// Loop de aceptación de conexiones
}).start();
Pseudocódigo:
EJECUTAR_EN_NUEVO_HILO(
// Loop de aceptación de conexiones
)
Paso 4: Aceptación de la Conexión del Cliente
Dentro del hilo, la aplicación entra en un bucle infinito y se detiene esperando a que un cliente (la terminal) se conecte. Cuando esto ocurre, se crea un objeto Socket que representa el canal de comunicación privado con ese cliente.
Socket clientSocket;
while (true) {
clientSocket = serverSocket.accept();
// La terminal queda conectada por esta LAN, sin importar
// qué IP le asignó el switch/router al equipo
}
Pseudocódigo:
INICIO
MIENTRAS verdadero
ESPERAR por conexión entrante EN socketServidor
clienteSocket = ACEPTAR conexión
FIN MIENTRAS
FIN
Paso 5: Asignación a un Gestor Dedicado
Ese Socket se entrega a un objeto CommunicationHandler, que se especializa en gestionar la conversación con un solo cliente. Este gestor también se inicia en su propio Thread para manejar el envío y la recepción de forma independiente.
handler = new CommunicationHandler(clientSocket);
Thread communicationThread = new Thread(handler::run);
communicationThread.start();
Pseudocódigo:
// Crear un nuevo gestor de comunicación para este cliente
hiloDeComunicacion = CREAR CommunicationHandler(clienteSocket)
// Iniciar el hilo dedicado a este cliente
INICIAR hiloDeComunicacion EN NUEVO HILO
Nota: si la PC llega a tener más de un adaptador de red activo al mismo tiempo (por ejemplo Wi-Fi y Ethernet), escuchar en
0.0.0.0evita tener que elegir una sola interfaz en el código del Bridge — la responsabilidad de usar la IP correcta pasa al instalador, que la captura del lado de la terminal (ver Paso 4 de «Arquitectura Switch»).
Mantener la conexión activa (Heartbeat)
La Pagando Check Pad² mantiene, del lado de la terminal, un timeout de lectura sobre el socket de conexión: si no recibe ningún dato del Bridge dentro de una ventana de 20 segundos, asume que la conexión se perdió y reinicia el ciclo de reconexión.
En una red compartida por switch, la terminal y la PC no están unidas por un enlace directo entre sí, por lo que una pérdida de conexión (apagado imprevisto del equipo controlador, cable desconectado, falla del switch, partición de la red) no siempre se traduce en un cierre explícito del socket del lado de la terminal: el socket puede quedar «abierto» a la espera de datos que ya no llegarán. Durante los periodos sin ventas ni operaciones tampoco existe tráfico natural entre ambos extremos que mantenga viva esa ventana de 20 segundos.
Por esto, el Bridge debe generar tráfico artificial de forma periódica: el heartbeat.
Rol del Bridge en el heartbeat
- Enviar, de forma periódica y mientras la conexión con la terminal esté activa, un mensaje JSON de heartbeat.
- El intervalo de envío debe ser menor a los 20 segundos del timeout de lectura de la terminal, dejando margen para la latencia de la red. Se recomienda un intervalo entre 10 y 15 segundos.
- El heartbeat es de un solo sentido (Bridge → Terminal): la terminal lo recibe, lo descarta silenciosamente y no envía ninguna respuesta. El Bridge no debe esperar una confirmación de este mensaje.
- El envío del heartbeat no debe interrumpir ni retrasar el envío de mensajes operativos (cobro, consulta de estatus, etc.); ambos flujos comparten el mismo socket de escritura.
Formato del mensaje
{"actionType": "HEARTBEAT"}Mismo esquema de acción (actionType) usado por el resto de los mensajes del protocolo.
Paso 6: Definir el intervalo de heartbeat
private static final int HEARTBEAT_INTERVAL_MS = 12000; // 12 segundosPseudocódigo:
DEFINIR intervaloHeartbeatMs COMO ENTERO = 12000 // margen sobre el
// timeout de 20s de la terminalPaso 7: Enviar el heartbeat en un ciclo independiente
El heartbeat debe correr en su propio hilo (o temporizador), iniciado en cuanto el Bridge acepta la conexión de la terminal (Paso 4), sin bloquear el hilo principal de escucha y envío de mensajes operativos.
private void startHeartbeat(Socket clientSocket) {
new Thread(() -> {
try {
while (clientSocket.isConnected() && !clientSocket.isClosed()) {
sendHeartbeat(clientSocket);
Thread.sleep(HEARTBEAT_INTERVAL_MS);
}
} catch (Exception e) {
// El hilo termina si el socket se cierra o falla el envío;
// el ciclo de reconexión del Bridge se encarga del resto.
}
}).start();
}
private synchronized void sendHeartbeat(Socket clientSocket) throws IOException {
PrintWriter writer = new PrintWriter(clientSocket.getOutputStream(), true);
writer.println("{\"actionType\":\"HEARTBEAT\"}");
}Pseudocódigo:
PROCEDIMIENTO IniciarHeartbeat(socketCliente)
EJECUTAR_EN_NUEVO_HILO(
MIENTRAS socketCliente.estaConectado Y NO socketCliente.estaCerrado
EnviarHeartbeat(socketCliente)
ESPERAR intervaloHeartbeatMs
FIN MIENTRAS
)
FIN PROCEDIMIENTO
PROCEDIMIENTO SINCRONIZADO EnviarHeartbeat(socketCliente)
ESCRIBIR EN socketCliente '{"actionType":"HEARTBEAT"}'
FIN PROCEDIMIENTONota: si el Bridge ya cuenta con un canal de escritura compartido para los mensajes operativos (el mismo usado por el
CommunicationHandlerdel Paso 5), el heartbeat debe usar ese mismo canal de forma sincronizada (synchronized/mutex). Dos hilos escribiendo al socket al mismo tiempo pueden intercalar bytes de dos mensajes JSON distintos y corromper ambos.
Paso 8: Detener el heartbeat al perder la conexión
Cuando el Bridge detecta que la terminal se desconectó (excepción al escribir o al leer del socket), debe detener el ciclo de heartbeat de esa conexión antes de volver a esperar una nueva conexión entrante — seguir escribiendo sobre un socket cerrado sólo genera excepciones adicionales sin ningún efecto útil.
Nota: el heartbeat es responsabilidad exclusiva del Bridge. La terminal ya reconoce el mensaje de heartbeat y lo descarta sin generar respuesta ni afectar el proceso de cobro en curso; no requiere ninguna configuración adicional de parte del instalador.