Vamos criar um mini messenger, na verdade o esqueleto de um só para ter como base para criar outros.
Antes baixe a versão mais atual Prisma, 1.0.99 ou superior.
(Testado em Ubuntu 12.04, Mint17, Mint18 e Windows7,10)
1- Servidor
Primeiramente, vamos criar o servidor, programa que vai receber as mensagens do cliente. Salve como servidor.prisma, e copie o código abaixo:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
inclua'igrede'; inclua 'igbr'; bloco_tam = 1024;//tamanho do bloco; 1024 caracteres //funcao principal funcao principal() local servidor = igrede.servidor(); ret, erro_msg = igrede.escute_porta(servidor, 2345); se ret == falso entao imprima(erro_msg); sis.saia(1); fim ig.conecte_funcao(servidor,ig.recebido, call_servidor,nulo); igrede.servidor_inicie(servidor); imprima'Servidor ativo, esperando conexao com cliente'; ig.fimprograma(); igrede.servidor_pare(servidor); retorne 0; fim //fim principal funcao ao_ler(mensagem,dado) imprima("Cliente: " .. mensagem); fim funcao call_servidor( servidor,conexao, Gobjeto, dado) imprima("Conexao recebida de cliente\n"); igrede.leia_assinc( conexao, bloco_tam, ao_ler,dado);//executa leitura assincrona, com 1024 bytes de tamanho. fim |
Vamos aos detalhes:
1 2 |
inclua'igrede'; inclua 'igbr'; |
No trecho acima incluímos as bibliotecas necessárias, veja que igbr é necessária mesmo que não usemos interface gráfica.
As duas bibliotecas acima trabalham juntas.
1 |
bloco_tam = 1024;//tamanho do bloco; 1024 caracteres |
Na linha acima definimos qual será o tamanho máximo de cada dado enviado ao servidor. 1024 bytes é o limite, correspondente a 1Kb aproximadamente.
1 |
funcao principal() |
Aqui iniciamos a função principal(), o mesmo que main() do C.
1 |
local servidor = igrede.servidor(); |
A função acima cria um ponteiro servidor e salva em uma variável.
1 |
ret, erro_msg = igrede.escute_porta(servidor, 2345); |
Aqui fazemos o servidor escutar na porta 2345;
Parâmetros:
1- servidor criado com a função igrede.servidor();
2 – Número da porta, tome cuidado para que a porta não seja a mesma que outro programa use, ex.: servidor usa porta 80, Mysql usa 3306 etc.
Retornos:
1 – ret: é um boleando falso para erro.
2 – erro_msg: mensagem de erro em string.
(Talvez eu modifique estes retornos, não faz sentido dois)
1 2 3 4 |
se ret == falso entao imprima(erro_msg); sis.saia(1); fim |
Acima é feito o tratamento de erro. Se ret for igual a falso então a mensagem de erro é impressa e o programa é fechado.
1 |
ig.conecte_funcao(servidor,ig.recebido, call_servidor,nulo); |
Conectamos uma função callback (call_servidor) ao evento recebido do servidor. Ou seja, cada vez que o servidor receber algo do cliente esta função será executada. O último parâmetro (dado extra) é nulo pois não vamos usá-lo.
1 |
igrede.servidor_inicie(servidor); |
No trecho acima, iniciamos o servidor, passamos a variável do servidor com parâmetro para função igrede.servidor_inicie();
Após isso, imprimimos a frase de espera:
1 |
imprima'Servidor ativo, esperando conexao com cliente'; |
1 |
ig.fimprograma(); |
A função acima inicia o laço de eventos do igbr. Ao chegar aqui o programa entra em modo repetição esperando eventos como clique do mouse, tecla pressionada etc. O que estiver após esse comando só será executado quando o laço for interrompido.
1 2 3 |
igrede.servidor_pare(servidor); retorne 0; fim //fim principal |
Este último comando, como pode-se perceber pelo nome, finaliza o servidor.
Enfim, é retornado 0 e fechamos a função principal com seu respectivo fim.
Vamos para as funções callbacks:
1 2 3 |
funcao ao_ler(mensagem,dado) imprima("Cliente: " .. mensagem); fim |
Esta função está conectada à leitura do servidor. Ao ser executada automaticamente pela função leia_assinc() ela recebe a mensagem recebida e o dado extra.
1 |
funcao call_servidor( servidor, conexao, Gobjeto, dado) |
Esta função acima foi conectada ao evento recebido do servidor, logo ela será executada sempre que o servidor receber uma mensagem do cliente. Seus parâmetros são passados automaticamente a cada execução da função pelo evento ‘recebido’.
Parâmetros da callback: Servidor ativo, a conexão, o objeto, e o dado extra que no caso é nulo, pois foi definido assim na função conecte_funcao();
1 2 3 |
imprima("Conexao recebida de cliente\n"); igrede.leia_assinc( conexao, bloco_tam, ao_ler,dado);//executa leitura assincrona, com 1024 bytes de tamanho. fim |
Corpo da função callback.
imprimimos a mensagem de conexão recebida.
usamos a função igrede.leia_assinc() para ler a mensagem.
Parâmetros:
1 – conexao: ponteiro da conexao recebida, é o segundo parâmetro da callback.
2 – tamanho em bytes máximo para ler a mensagem.
3 – função extra para receber a mensagem.
Enfim, a função callback é fechada com ‘fim’;
Aqui finalizamos a primeira parte, e a mais complicada, agora vamos ao programa cliente.prisma:
2 – Cliente
Salve como cliente.prisma e copie o código abaixo:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
socket = inclua'igrede' cliente = socket.cliente();//cria um novo cliente socket repita //fazemos um laco repita para digitar as mensagens. imprima'Digite algo: [s = sair]' s = leia(); se s == 's' entao sis.saia(0); fim //conectando-se ao servidor 'localhost' na porta 2345 conexao , erro_msg = socket.cliente_conecte_com_servidor (cliente , "192.168.1.12", //ip do servidor 2345 //porta de conexao ); se conexao == nulo entao imprima( erro_msg,'\nConexao rejeitada, servidor desligado?' ); //sis.saia(4); senao imprima("Enviado com sucesso para o servidor"); erro_msg = socket.escreva( conexao , s ); se erro_msg entao imprima(erro_msg) fim; fim ate s == 's'; //fim sis.saia(0); |
Detalhes:
1 |
socket = inclua'igrede' |
Incluindo a biblioteca igrede. Aqui não precisamos da igbr.
1 |
cliente = socket.cliente();//cria um novo cliente socket |
Criando um socket cliente e retornando na variável cliente.
1 2 |
repita //fazemos um laco repita para digitar as mensagens. imprima'Digite algo: [s = sair]' |
Vamos usar o comando repita como laço de repetição, poderia ser o enquanto se quisesse.
Imprimimos a frase do cabeçalho do messenger.
1 |
s = leia(); |
Essa função aguarda o usuário digitar algo e pressionar ENTER, no nosso caso a frase para enviar ao servidor ou S para sair:
1 |
se s == 's' entao sis.saia(0); fim |
se o usuário digitar S o programa é fechado.
1 2 3 |
conexao , erro_msg = socket.cliente_conecte_com_servidor (cliente , "192.168.1.12", //ip do servidor 2345 //porta de conexao ); |
A função que conecta ao servidor.
Parâmetros:
1 – cliente: variável ponteiro do cliente criado com a função socket.cliente();
2 – Ip do servidor. Substitua por um ip válido em sua rede. Ou se estiver executando servidor e cliente no mesmo pc use ‘localhost’.
3 – Porta do servidor. Use a mesma definida no servidor.prisma
Retornos:
1 – conexao: variável ponteiro da conexão com o servidor ou nulo caso a conexão falhe.
2 – erro_msg: string descrevendo mensagem de erro se houver.
1 2 3 |
se conexao == nulo entao imprima( erro_msg,'\nConexao rejeitada, servidor desligado?' ); //sis.saia(4); |
Acima fazemos o tratamento de erro. Se conexao for nulo imprimimos o erro no terminal e poderíamos sair do programa se quiser (des)comente a função sis.saia(4);
1 2 3 |
senao imprima("Enviado com sucesso para o servidor"); erro_msg = socket.escreva( conexao , s ); |
Caso não haja erro, a frase de sucesso é impressa e usamos a função socket.escreva() para escrever no servidor (enviar a mensagem) o texto digitado em s;
Parâmetros:
1 – conexao: a variável ponteiro da conexão realizada com o servidor.
2 – s : string a ser enviada para o servidor.
Retornos:
1 – erro_msg: string descrevendo erro ou nulo caso não haja erro.
1 2 |
se erro_msg entao imprima(erro_msg) fim; fim |
Tratamento de erro: imprimimos o erro.
fim para fechar o comando ‘se conexao == nulo…
Dicas:
Para transferir arquivos basta fazer a leitura binária, obter o conteúdo em forma de string, se preferir pode codificar para base64 usando a função string.base64 e assim evitar conflito com caracteres especiais e do lado do servidor é só decodificar string.dec_base65(), e salvar em um arquivo com a escrita binária.
Desafio: crie um programa que seja cliente e servidor simultâneo para enviar e receber mensagem.
Prints dos resultados:
Até a próxima, vamos ver quem consegue aprimorar e criar um messenger profissional!!!
Att. Adalberto
Boa noite Adalberto,
Seria possível fazer esse servidor/cliente na camada de enlace (camada 2 MAC) usando o protocolo LCP ao invés de TCP ?
Quero fazer um servidor Ponto a Ponto tipo PPPOE para autenticação de usuários.
Qual biblioteca em C você usa para desenvolver a igrede ?
Olá, Rafael. Por enquanto não. essa lib é bem limitada, planejava fazer algo com sockets assim que puder.
A lib ig rede usa os cabeçalhos: glib.h e gio/gio.h
Vou tentar trabalhar com sockets em breve, aí eu posto no fórum e site.
Olha só, tentei por várias maneiras em colocar o servidor e cliente no mesmo programa inclusive vi alguns exemplos em python, mas não consegui.
Eu sempre paro em ig.fimprograma();
quando coloco um laço antes ele não executa o que o cliente digita.
Pelo que entendi teria que colocar o cliente dentro do laço ig.fimprograma(); mas não tenho acesso a clib;
Blz Rafael. Vou fazer um exemplo e up ok? Ah, tem uma lib wrapper da libCurl a caminho, é tanta coisa que nem sei qual eu faço primeiro, mas estou quase terminando. Há uma função que torna possível substituir o ig.fimprograma() por um laço enquanto, mas tem algumas desvantagens. Aguarde que já vejo isso hoje, ok.
E aí Rafael. Veja o post Mini messenger… no site, acabei de postar.
Link: http://linguagemprisma.br4.biz/blog/igprisma/mini-messenger-em-prisma-ig-igrede/
Não testei muito ainda, mas dá para ter uma noção, blz.
Oi, ja faz um tempo que eu estudo tua linguagem, e quero usar para criar um programa para um cliente mas como faço para converter o prisma para executável? nao quero ter que dizer para o usuário instalar o interpretador para executar o programa. quero um .exe voce tem alguma noção de quando vai sair?
Olá, já tem uma solução pronta, só tenho que atualizar para versão 1.0,102;
É o srprisma uma espécie de auto-contêiner, o código prisma fica embutido no *.exe, vou postar logo e aviso aqui nas respostas, ok.
O sistema do seu cliente é Windows né?
(Você converte de .prisma para .exe, depois só montar uma pasta com todas as dlls necessárias e bibliotecas prisma. Basta colocar o *.exe dentro desta pasta e criar o instalador.)
Blz, já fiz o update do srprisma para 1.0.102, só seguir esse link, ok:
http://linguagemprisma.br4.biz/blog/prisma/convertendo-um-script-prisma-para-exe/