CAPÍTULO
6 Programação visual com Software Livre EDIT LIN EDITORIAL S.L, dos autores Daniel Campos Fernández e José Luis Redrejo. Prólogo de Benoit Minisini |
|
<< Anterior | Próximo >> |
6.2 Criando um servidor TCP Nossa primeira tarefa
consistirá em escrever o código de um servidor TCP:
será um servidor que aceita conexões remotas,
lerá
os dados enviados e devolverá um eco aos clientes. Criaremos
um
programa de console chamado MeuServidor.
Este programa terá um único módulo
chamado ModMain.
E nas propriedades do projeto selecionaremos o componente gb.net.
Dentro do módulo ModMain teremos uma referência a um objeto ServerSocket. Estes objetos comportam-se como servidores de socketes, quer dizer, encontram-se a escuta de petições de clientes remotos em um porta determinada. As portam são numeradas de 1 a 65535 e cada programa que atua como servidor dentro do sistema utiliza uma delas. |
|
z![]() Figura 1.Programa MeuServidor. |
|
As portas com número de 1 a 1024, se consideram reservadas para serviços conhecidos (HTTP, POP FTP, IMAP...) e podem ser utilizados por programas cujo usuário é diferente de root em sistemas GNU/Linux. Tratar, por tanto, de abrir, por exemplo, a porta 523 a partir de um programa executado por um usuário normal, dará um erro. | |
Os
serviços mais conhecidos como HTTP ou FTP já
tem uma porta designada (por exemplo, 80 no caso de HTTP)
de forma padrão, se bem que não há
nenhuma
razão técnica pela qual um servidor web
não possa
atender, por exemplo, a porta 9854. Esto se deve unicamente a um acordo
internacional para que qualquer cliente que queira realizar uma
petição web, saiba que, salvo
instruções
especificas ao contrário, terá que conectar-se a
porta 80
da maquina servidora.
|
|
Em sistema GNU/Linux podemos encontrar uma lista dos serviços mais comuns e suas portas oficiais dentro do arquivo de texto /etc/services | |
Em nosso caso
vamos utilizar a
porta 3152. Na função Main do programa,deveremos
criar o
objeto ServerSocket, especificar que seu tipo será internet
(isso se for um socket TCP
e não UNIX),
a porta que deve atender e indicar-lhe que comece com as
petições.
|
|
PRIVATE
Servidor AS
ServerSocket
PUBLIC SUB Main() Servidor = NEW ServerSocket AS "Servidor" Servidor.Type = Net.Internet Servidor.Port = 3152 TRY Servidor.Listen() IF ERROR THEN PRINT "Erro: oo sistema não permite atender a porta especificada" END |
|
Observamos que na
hora de criar
o objeto servidor, indicamos que o gestor de eventos será
"Servidor", para poder escrever as rotinas nas quais tratemos
as
petições que chega dos clientes.
Na hora de indicar ao servidor que ponha-se a escutar com o método listen, o fazemos protegendo o código com uma instrução TRY, para gestionar o erro se o sistema não permitir atender a porta indicada (por exemplo, se outro serviço já o estiver utilizando). Já podemos executar o programa. Como podemos observar, o programa passa a função Main e segue executando a espera da conexão de um. Um programa normal de console, ao terminar esta função, teria finalizado sem mais, mas neste caso o interpretador Gambas está atendendo as novidades que podem aparecer no socket que foi criado e, por tanto, o programa segue funcionando, esperando petições de clientes. |
|
Qualquer programa Gambas que está vigiando um descritor, ou seja, um arquivo, um processo ou um socket, não finaliza enquanto esse descritor se encontre aberto. Esta técnica permite criar programa de console que não ficam em um loop continuo a espera de novidades (seja uma modificação em um arquivo, uma entrada de um cliente em um socket ou a leitura de dados de um processo filho), poupando recursos e melhorando a eficácia do processo. | |
O programa
servidor já está
funcionando, enquanto não haja nada realmente
útil. Pra fazer, se
testarmos ao conectarmos a partir do console com o programa telnet em
nosso próprio servidor, observaremos que conecta-se e
imediatamente
desconecta-se do servidor.
|
![]() Figura 2.
Teste de conexão.
|
O funcionamento do
objeto
ServerSocket é precisamente este: recebe uma
conexão de
um cliente e, se não especificarmos ao programa que
desejamos
atende-la, a fecha.
Quando um objeto servidor recebe uma petição de um cliente, dispara o evento Connection. Dentro desse evento, e só dentro dele, podemos utilizar o método Accept. Esse método devolve um objeto Socket que representa uma conexão com esse cliente. Na hora de receber e enviar dados a esse cliente, faremos através desse objeto, desse modo, se diferencia a cada cliente conectado com um servidor de forma única, evitando, por exemplo, que enviamos o resultado de um calculo a um cliente equivocado. Em nosso programa adicionaremos uma matriz de objetos onde guardaremos uma referencia a cada cliente, e nessa matriz iremos adicionando os clientes que iram conectar-se. |
|
PRIVATE
Servidor AS
ServerSocket
PRIVATE Clientes AS NEW Object[] PUBLIC SUB Servidor_Connection(RemoteHostIP AS String) DIM Cliente AS Socket Cliente = Servidor.Accept() Clientes.Add(Cliente) END PUBLIC SUB Main() Servidor = NEW ServerSocket AS "Servidor" Servidor.Type = Net.Internet Servidor.Port = 3152 TRY Servidor.Listen() IF ERROR THEN PRINT "Erro: O sistema não permite atender a porta especificada" END |
|
Em nosso gestor de eventos
Connection utilizamos o método
Accept, para que sempre aceitemos as conexões de entrada. No
entanto, se o omitimos em casos determinados, a tentativa de
conexão do cliente encerra-se automaticamente. Observamos,
por
exemplo, que Accept nos informa do endereço IP do cliente
que
trata de conectar-se através do parâmetro
RemoteHostIP. Se desejarmos, por exemplo, aceitar
só
conexões a partir de nosso próprio equipamento
(que
sempre tem endereço 127.0.0.1),
poderíamos
modificar o código para que recuse as conexões de
outros
endereços IP. |
|
PUBLIC SUB
Servidor_Connection(RemoteHostIP AS
String)
DIM Cliente AS Socket IF RemoteHostIP = "127.0.0.1" THEN Cliente = Servidor.Accept() Clientes.Add(Cliente) END IF END |
|
Este objeto
socket, por padrão recebem um gestor de eventos chamado Socket, pelo qual os
eventos dos clientes de socket se entendem no programa por um
função chamada Socket_ + Nome do evento.
Em nosso caso utilizamos os eventos Read produzido quando se recebe dados vindo dos clientes, e o evento Close, que ocorre quando quando o cliente encerra a conexão. No caso do evento READ, nos valemos da palavra chave LAST, que mantem uma referência ao último objeto que disparou um evento (neste caso, o cliente de socket) para tratar os dados que provem dele. Para isso, leremos o socket como se fosse um arquivo, com a instrução READ, no qual indicamos a cadeia que recebe os dados; leremos o comprimento dos dados disponíveis no sockt, determinada pela função Lof() e, depois escreveremos esses mesmos dados no socket com a instrução WRITE, de forma que o cliente receba um eco dos dados enviados, mas convertidos em maiúsculas. |
|
PUBLIC
SUB Socket_Read()
DIM sCad AS String TRY READ #LAST, sCad, Lof(LAST) sCad = UCase(sCad) TRY WRITE #LAST, sCad, Len(sCad) END |
|
Para Close, buscamos o objeto Socket
dentro de nossa matriz e o
eliminamos para que desapareçam as referências a
esse
cliente dentro de nosso programa servidor. |
|
PUBLIC
SUB Socket_Close()
DIM Ind AS Integer Ind = Clientes.Find(LAST) IF Ind >= 0 THEN Clientes.Remove(Ind) END |
|
Já dispomos de um
programa servidor de socket com a capacidade
para atender a múltiplos clientes: podemos abrir
várias
janelas de terminal, executando nelas telnet 127.0.0.1 352, e
enviar e receber dados do servidor. Cada vez que escrevemos uma cadeia
e a enviamos pressionando Return,
receberemos a cadeia convertida em maiúsculas como resposta
do servidor. |
|
Ainda que, o programa telnet foi criado pára controlar um equipamento de forma remota, também é um cliente universal que pode servir para comprovar o funcionamento de qualquer servidor que estejamos construindo, antes de dispor de um cliente real. | |
![]() Figura 3.Programa servidor de socket. |
|
<< Anterior | Próximo >> |
Cópia literal Extraído
do livro “GAMBAS, programação visual
com software
Livre”, da editora EDIT LIN EDITORIAL S.L, dos
autores Daniel Campos Fernández e José
Luis
Redrejo. Prólogo de Benoit
Minisini
LICENSA DESTE DOCUMENTO É
permitido a cópia e
distribuição da
totalidade ou parte desta obra sem fins lucrativo. Toda
cópia
total ou parcial devera expressar o nome do autor e da editora e
incluir esta mesma licença, adicionando se é uma
cópia literal “Cópia
literal”. Se é
autorizada a modificação e
tradução da
obra sem fins lucrativo sempre se deve constar na obra
resultante a modificação o nome da obra
original o
autor da obra original e o nome da editora e a obra resultante
também deverá ser livremente reproduzida,
distribuída, ao publico e transformada em termos similares
ao
exposto nesta licença.
Tradução Cientista (Antonio Sousa) |
|