Nova classe para lidar com ligações TCP de entrada

Em 4D 20 R8, introduzimos a classe TCPConnection, permitindo iniciar conexões TCP a servidores remotos. Com 4D v20 R9, estamos entusiasmados em trazer a classe TCPListener – sua chave para lidar com conexões TCP de entrada e construir um servidor TCP diretamente em 4D.

Com estas duas classes – TCPConnection e TCPListener – tem agora controlw total sobre a comunicação TCP, tanto do lado do cliente como do lado do servidor.

Vamos ver como usá-las juntas.

HDI TCPConnections

Antes de mergulhar neste post, é altamente recomendável verificar nosso post anterior no blog sobre a classe TCPConnection para entender a base sobre a qual estamos construindo.

 

Como as classes TCPListener e TCPConnection interagem

Definindo a classe de conexão

Criaremos uma nova classe chamada ServerSideConnection, modelada de acordo com a classe ConnectionToTheServer usada no exemplo anterior. Aqui está um detalhamento dos principais retornos de chamada que você implementará:

Class constructor()

//Callback chamada quando a conexão for estabelecida com sucesso
Function onConnection($connection : 4D.TCPConnection; $event : 4D.TCPEvent) 
	ALERT("Connection established") 

//Callback chamada quando a conexão for fechada com sucessso
Function onShutdown($connection : 4D.TCPConnection; $event : 4D.TCPEvent) 
	ALERT("Connection closed") 

//Callback chamada quando receber dados. Os servidores simples sempre enviam uma sentença para mostrar ao usuário
Function onData($connection : 4D.TCPConnection; $event : 4D.TCPEvent) 
	ALERT(BLOB to text($event.data; UTF8 text without length)) 

//Callback chamada quando a conexão for fechada inesperadamente
Function onError($connection : 4D.TCPConnection; $event : 4D.TCPEvent) 
	ALERT("Connection error")

Esta classe é um shell direto que reage aos principais eventos TCP.

Configurando a classe de ouvinte

Agora, vamos criar uma classe ServerListener para escutar em uma porta específica e aceitar conexões de entrada:

property listener:4D.TCPListener

shared singleton Class constructor()

//Começa a ouvir uma porta dada como parâmetro
shared Function startListening($port:integer)
	This.listener:=4D.TCPListener.new($port, This)

//Para de ouvir
shared Function stopListening()
	This.listener.terminate()

//Callback chamada em uma nova conexão entrante	
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 chamada quando um erro prevenir a escuta da porta (em geral devido ao conflito com outra aplicação)
Function onError($listener : 4D.TCPListener; $event : 4D.TCPEvent)
	
	ALERT("Listener: onError")

Para iniciar o listener, use:

cs.ServerListener.me.startListening($port)

Sempre que um cliente tentar se conectar, o método onConnection é acionado. Você pode retornar um objeto ServerSideConnection para aceitar a conexão – ou retornar null para rejeitá-la. Uma vez aceito, as correspondentes chamadas de retorno TCPConnection entram em ação, permitindo-lhe tratar a ligação como qualquer outro cliente.

Para parar de escutar novas conexões, basta chamar:

cs.ServerListener.me.stopListening()

Nota: As conexões ativas permanecerão até que você as feche manualmente.

Estrutura de classe unificada = Código simplificado

Um grande benefício deste design é que a mesma classe TCPConnection é usada para conexões de cliente e servidor. Essa simetria simplifica sua implementação e promove a reutilização de código, pois o comportamento de ambas as extremidades da conexão pode compartilhar a mesma lógica e estrutura.

Conclusão

Com a adição da classe TCPListener no 4D v20 R9, pode agora criar servidores TCP robustos inteiramente em 4D. Emparelhado com TCPConnection, as novas ferramentas dão-lhe uma estrutura completa para lidar com comunicação TCP de duas vias – limpa, eficiente e com duplicação mínima de código.

Se tiver alguma pergunta ou feedback, não hesite em trazê-los para o fórum 4D.

Nicolas Brachfogel
• Proprietário do produto e Desenvolvedor Senior -Nicolas Brachfogel entrou a 4D em 2017 como Senior Developer (4D Server e Networking). Como Product Owner para gerenciar o lançamento de Apple Silicon, está a cargo de escrever as histórias dos usuários e depois traduzi-las em especificações funcionais, além de garantir que as implementações de funcionalidade cumpram com as necessidades do cliente. Diplomado pelo Instituto Superior de Informática Aplicada (INSIA), Nicolas começou sua carreira como desenvolvedor de software em 2001. Depois de vários anos codificando em Java e C++, passou a especializar-se no desenvolvimento cliente-servidor para empresas de videogames. Como desenvolvedor/arquiteto de servidores, trabalhou com sucesso nas arquiteturas de servidores de muitos jogos (Dofus Arena, Drakerz, Trivial Pursuit Go!)