Cliente e servidor socket em Golang com tratamento de sinais.
Continuando nossa série de artigos sobre cliente/servidor, adicionaremos um novo canal no exemplo anterior. Esse canal tratará sinais enviados pelo sistema operacional.
O sistema operacional envia sinais aos programas para gerenciar processos. Por exemplo, ao pressionar Ctrl+C, o sistema operacional envia o sinal SIGINT, informando o programa que o usuário deseja interrompê-lo.
Por padrão, o programa é fechado. Porém, podemos interceptar esse sinal e agir conforme necessário. Neste caso, apenas finalizaremos o programa. Em sistemas reais, esse recurso pode ser usado para salvar informações antes de fechar, encerrar outros processos, fechar conexões e arquivos, entre outros. Esse processo é conhecido como graceful shutdown.
Servidor
No servidor, criamos um canal e informamos ao sistema para enviar sinais por esse canal. Também criamos uma goroutine para monitorar o canal.
sigs := make(chan os.Signal, 1)
signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM)
go func() {
<-sigs
fmt.Println("\nShutdown server...")
os.Exit(0)
}()
Cliente
No cliente, a abordagem é diferente. Não precisamos criar uma goroutine. Como já estamos utilizando select case para tratar canais, basta adicionar o novo canal aos cases existentes. Ele será tratado normalmente, assim como os outros canais.
sigs := make(chan os.Signal, 1)
signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM)
for {
select {
case <-sigs:
fmt.Println("\nDisconnecting...")
conn.Close()
os.Exit(0)
...
Código-fonte
Confira o código-fonte do nosso servidor e cliente:
Vídeos com explicação
Conclusão
A alteração para adicionar o tratamento de sinais foi simples, mas essencial. Ao fechar o programa, é importante garantir que ele esteja em um estado consistente. Por exemplo, se o programa salva dados em um banco de dados, é recomendável esperar que as transações abertas sejam concluídas antes de encerrar o programa.