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.
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.