Go é uma linguagem open source lançada, em 2009, pelo Google e criada por Robert Griesemer, Rob Pike e Ken Thompson.
Uma das coisas mais bacanas de Go é poder escrever código de forma simples, pouco verborrágica, estruturada e bastante eficaz, sem contar que é uma linguagem fortemente tipada, incrivelmente leve e suporta concorrência nativamente através de goroutines.
Dentre muitos pacotes, Go através do pacote “net” provê interfaces de acesso a I/O, incluindo a pilha TCP/IP, UDP, resolução por nome de domínio e UNIX Sockets.
Com uma ideia muito simples, neste artigo, iremos criar um cliente e um servidor TCP/IP que servirá para observarmos os principais aspectos destas implementações.
Para tal, vamos estabelecer um protocolo de comunicação bastante básico entre as duas aplicações para garantir que ambos, cliente e servidor, consigam executar suas tarefas.
Servidor
O protocolo de comunicação que nosso servidor deverá trabalhar será este:
- Ouvir a interface tcp na porta 8081;
- Aceitar conexões;
- Dentro de um loop infinito, ouvir as mensagens a serem transmitidas pelo cliente;
- Escrever no terminal estas mensagens;
- Devolver a mensagem recebida ao cliente (eco).
package main import ( "bufio" "fmt" "net" "os" "strings" ) func main() { fmt.Println("Servidor aguardando conexões...") // ouvindo na porta 8081 via protocolo tcp/ip ln, erro1 := net.Listen("tcp", ":8081") if erro1 != nil { fmt.Println(erro1) /* Neste nosso exemplo vamos convencionar que a saída 3 está reservada para erros de conexão. IMPORTANTE: defers não serão executados quando utilizamos os.Exit() e a saída será imediata */ os.Exit(3) } // aceitando conexões conexao, erro2 := ln.Accept() if erro2 != nil { fmt.Println(erro2) os.Exit(3) } defer ln.Close() fmt.Println("Conexão aceita...") // rodando loop contínuo (até que ctrl-c seja acionado) for { // Assim que receber o controle de nova linha (\n), processa a mensagem recebida mensagem, erro3 := bufio.NewReader(conexao).ReadString('\n') if erro3 != nil { fmt.Println(erro3) os.Exit(3) } // escreve no terminal a mensagem recebida fmt.Print("Mensagem recebida:", string(mensagem)) // para um exemplo simples de processamento, converte a mensagem recebida para caixa alta novamensagem := strings.ToUpper(mensagem) // envia a mensagem processada de volta ao cliente conexao.Write([]byte(novamensagem + "\n")) } }
Cliente
O protocolo de comunicação que nosso cliente deverá trabalhar será este:
- Conectar-se a interface tcp localhost na porta 8081;
- Dentro de um loop infinito, realizar leitura do terminal;
- Escrever no socket a mensagem digitada no terminal (transmitir);
- Ouvir o retorno do servidor;
- Escrever no terminal a mensagen retornada (eco).
package main import "net" import "fmt" import "bufio" import "os" func main() { // conectando na porta 8081 via protocolo tcp/ip na máquina local conexao, erro1 := net.Dial("tcp", "127.0.0.1:8081") if erro1 != nil { fmt.Println(erro1) os.Exit(3) } for { // lendo entrada do terminal leitor := bufio.NewReader(os.Stdin) fmt.Print("texto a ser enviado: ") texto, erro2 := leitor.ReadString('\n') if erro2 != nil { fmt.Println(erro2) os.Exit(3) } // escrevendo a mensagem na conexão (socket) fmt.Fprintf(conexao, texto+"\n") // ouvindo a resposta do servidor (eco) mensagem, err3 := bufio.NewReader(conexao).ReadString('\n') if err3 != nil { fmt.Println(err3) os.Exit(3) } // escrevendo a resposta do servidor no terminal fmt.Print("Resposta do servidor: " + mensagem) } }
Para ter uma boa experiência deste exemplo, execute primeiramente o tcp-server e, em seguida, o tcp-client preferencialmente em terminais diferentes para acompanhar o resultado.
Veja o resultado:
Servidor:
Cliente:
Servidor:
Cliente / Servidor:
Obviamente existem tratamentos que devem ser realizados quanto a quebra de protocolo, exceções decorrentes do processamento das mensagens ou perda de conexão por uma das partes, mas… isso é com vocês!
Conclusão, Go é muito divertido!
Para ajudar, confira os links abaixo: