Nueva clase para gestionar las conexiones TCP entrantes

En 4D 20 R8, introdujimos la clase TCPConnection, permitiéndole iniciar conexiones TCP a servidores remotos. Con 4D v20 R9, estamos entusiasmados de traerle la clase TCPListener, la llave para manejar conexiones TCP entrantes y construir un servidor TCP directamente en 4D.

Con estas dos clases-TCPConnection y TCPListener-usted tiene ahora control total sobre la comunicación TCP, tanto del lado del cliente como del lado del servidor.

Veamos cómo utilizarlas juntas.

Conexiones TCP de HDI

Antes de entrar de lleno en este artículo, le recomendamos que le dé un vistazo a nuestro artículo anterior sobre la clase TCPConnection para entender la base sobre la que estamos construyendo.

 

Cómo interactúan las clases TCPListener y TCPConnection

Definición de la clase DE conexión

Crearemos una nueva clase llamada ServerSideConnection, siguiendo el modelo de la clase ConnectionToTheServer utilizada en el ejemplo anterior. Aquí tiene un desglose de las principales retrollamadas que implementará:

Class constructor()

//Callback called when the connection is successfully established
Function onConnection($connection : 4D.TCPConnection; $event : 4D.TCPEvent) 
	ALERT("Connection established") 

//Callback called when the connection is properly closed
Function onShutdown($connection : 4D.TCPConnection; $event : 4D.TCPEvent) 
	ALERT("Connection closed") 

//Callback called when receiving data. The simple servers always send a sentence to show to the user
Function onData($connection : 4D.TCPConnection; $event : 4D.TCPEvent) 
	ALERT(BLOB to text($event.data; UTF8 text without length)) 

//Callback called when the connection is closed unexpectedly
Function onError($connection : 4D.TCPConnection; $event : 4D.TCPEvent) 
	ALERT("Connection error")

Esta clase es un sencillo intérprete de comandos que reacciona a los principales eventos TCP.

Configuración de la clase Listener

Ahora, vamos a crear una clase ServerListener para escuchar en un puerto específico y aceptar conexiones entrantes:

property listener:4D.TCPListener

shared singleton Class constructor()

//Start listening to the port given as parameter
shared Function startListening($port:integer)
	This.listener:=4D.TCPListener.new($port, This)

//Stop listening
shared Function stopListening()
	This.listener.terminate()

//Callback called on a new incoming connection	
Function onConnection($listener : 4D.TCPListener; $event : 4D.TCPEvent)->$result
	
	ALERT("Listener: onConnection")
	if ($event.IP = "a good IP address")
		$result:=cs.ServerSideConnection.new()
	else
		$result := null
	end if
	
//Callback called when an error prevents listening on the port (in general due to conflict with another application)
Function onError($listener : 4D.TCPListener; $event : 4D.TCPEvent)
	
	ALERT("Listener: onError")

Para iniciar el listener, usa:

cs.ServerListener.me.startListening($port)

Cada vez que un cliente intenta conectarse, el método onConnection es disparado. Puede devolver un objeto ServerSideConnection para aceptar la conexión o devolver null para rechazarla. Una vez aceptada, se activan las correspondientes retrollamadas TCPConnection, permitiéndote manejar la conexión como cualquier otro cliente.

Para dejar de escuchar nuevas conexiones, simplemente llame:

cs.ServerListener.me.stopListening()

Nota: las conexiones activas permanecerán hasta que las cierre manualmente.

Estructura de clases unificada = Código simplificado

Uno de los principales beneficios de este diseño es que la misma clase TCPConnection se utiliza tanto para conexiones cliente como servidor. Esta simetría simplifica su implementación y promueve la reutilización de código, ya que el comportamiento para ambos extremos de la conexión puede compartir la misma lógica y estructura.

Conclusión

Con la adición de la clase TCPListener en 4D v20 R9, ahora puede crear robustos servidores TCP completamente en 4D. Junto con TCPConnection, las nuevas herramientas le dan un marco de trabajo completo para manejar la comunicación TCP bidireccional, de manera limpia, eficiente y con mínima duplicación de código.

Si tiene alguna pregunta o comentario, no dude en plantearlo en el foro de 4D.

Nicolas Brachfogel
• Propietario de producto y Desarrollador Senior - Nicolas Brachfogel se unió a 4D en 2017 como Senior Developer (4D Server y networking). Como Product Owner para gestionar el lanzamiento de Apple Silicon, está a cargo de escribir historias de usuario y traducirlas en especificaciones funcionales, así como asegurarse de que las implementaciones de las funcionalidades satisfagan las necesidades del cliente. Diplomado por el Instituto Superior de Informática Aplicada (INSIA), Nicolas comenzó su carrera como desarrollador de software en 2001. Tras varios años codificando en Java y C++, pasó a especializarse en el desarrollo cliente-servidor para empresas de videojuegos. Como desarrollador/arquitecto de servidores, trabajó con éxito en las arquitecturas de servidores de muchos juegos (Dofus Arena, Drakerz, Trivial Pursuit Go!).