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:








