UDP Multicast

Esse é 13º artigo da série IPC. Demonstra o uso do UDP Multicast

Introdução

O UDP no modo broadcast permite enviar mensagens para todas as máquinas conectadas na rede de uma única vez, porém essa forma de envio pode prejudicar o desempenho da rede dependendo do tamanho e da frequência da mensagem enviada, para contornar esses problemas existe um modo conhecido como multicast, que é parecido com o broadcast mas envia a mensagem somente para as máquinas que estejam interessadas nesse conteúdo, dessa forma evita-se que haja um congestionamento na rede devido a replicação de mensagens para máquinas não interessadas. Para que as máquinas interessadas na mensagem transmitida, essas máquinas deverão se cadastrar em um grupo conhecido como IP multicast para que possam a partir desse registro receberem as mensagens.

Endereço Multicast

Para determinar o endereço multicast é necessário conhecer as classes de IP que são separadas em classes A, B, C, D e E. Para modo multicast foi reservado a classe D que é dedicado exclusivamente para esse propósito, possuindo um range de 224.0.0.0 até 239.255.255.255, dessa forma o emissor pode enviar para qualquer um desses endereços.

Representação do Multicast na rede

Quando uma mensagem multicast é enviada as máquinas registradas irão receber essas mensagens. Para ilustrar, o exemplo representa a transmissão de uma mensagem multicast.

AfraidUnitedHydatidtapeworm small

Na imagem é possível notar que as mensagem chegam somente nas máquinas interessadas

Selecionando o endereço multicast

Para selecionar o endereço de multicast para aplicação podemos pesquisar no site www.iana.org, que apresenta a finalidade de cada range.

De acordo com as recomendações, é selecionado o intervalo 232.192.0.0/24, sendo esse reservado para aplicações de uso privado, dentro desse range é selecionado o 239.192.1.1 como endereço do grupo multicast para a aplicação.

Preparação do Ambiente

Antes de apresentar o exemplo, primeiro é necessário instalar algumas ferramentas para auxiliar na análise da comunicação. As ferramentas necessárias para esse artigo são o tcpdump e o netcat(nc), para instalá-las basta executar os comandos abaixo:

netcat

O netcat é uma ferramenta capaz de interagir com conexões UDP e TCP, podendo abrir conexões, ouvindo como um servidor, ou como cliente enviando mensagens para um servidor.

tcpdump

O tcpdump é uma ferramenta capaz de monitorar o tráfego de dados em uma dada interface como por exemplo eth0, com ele é possível analisar os pacotes que são recebido e enviados.

Implementação

Para demonstrar o uso desse IPC, é adotado o modelo Cliente/Servidor, onde o processo Cliente(button_process) vai enviar uma mensagem via multicast para o servidor(led_process) que vai ler a mensagem, e verificar se corresponde com os comandos cadastrados internamente e processar o comando caso seja válido.

Biblioteca

A biblioteca criada permite uma fácil criação do servidor, sendo o servidor orientado a eventos, ou seja, fica aguardando as mensagens chegarem.

udp_multicast_receiver.h

Primeiramente é criado um callback responsável pelo tratamento de eventos de recebimento, essa função será chamada quando houver esse evento.

É criado também um contexto que armazena os parâmetros utilizados pelo servidor, sendo o socket para armazenar a instância criada, port que recebe o número que corresponde onde o serviço será disponibilizado, buffer que aponta para a memória alocada previamente pelo usuário, buffer_size o representa o tamanho do buffer, o callback para recepção da mensagem e o endereço do grupo multicast

Essa função inicializa o servidor com os parâmetros do contexto

Essa função aguarda uma mensagem publicada no grupo multicast pelo cliente.

udp_multicast_receiver.c

No UDP_Multicast_Receiver_Init é definido algumas variáveis para auxiliar na inicialização do servidor, sendo uma variável booleana que representa o estado da inicialização do servidor, uma variável do tipo inteiro para habilitar o reuso da porta caso o servidor precise reiniciar, uma estrutura sockaddr_in que é usada para configurar o servidor para se comunicar através da rede e uma estrutura utilizada para o registro do servidor no grupo multicast.

Para realizar a inicialização é criado um dummy do while, para que quando houver falha em qualquer uma das etapas, irá sair da função com status de erro, nesse ponto é verificado se o contexto, o buffer e se o tamanho do buffer foi inicializado, sendo sua inicialização de responsabilidade do usuário

É criado um endpoint com o perfil de se conectar via protocolo IPv4(AF_INET), do tipo datagram que caracteriza o UDP(SOCK_DGRAM), o último parâmetro pode ser 0 nesse caso.

A estrutura é preenchida com parâmetros fornecidos pelo usuário como em qual porta que o serviço vai rodar.

Aqui é habilitado o reuso do socket caso necessite reiniciar o serviço

É aplicada as configurações ao socket criado

O servidor é registrado no grupo multicast e é atribuído true na variável status

Na função UDP_Multicast_Receiver_Run é declarada algumas variáveis para receber as mensagens por meio do multicast

É verificado se o socket é válido e é aguardada uma mensagem no canal de multicast, a mensagem é repassada para o callback para realizar o tratamento de acordo com a aplicação do cliente, e é retornado o status.

udp_multicast_sender.h

É criado também um contexto que armazena os parâmetros utilizados pelo cliente, sendo o socket para armazenar a instância criada, hostname é o ip do canal multicast que vai ser enviado as mensagens e o port que recebe o número que corresponde onde o serviço vai ser disponibilizado

Inicializa o cliente com os parâmetros do descritor

Envia mensagem para o grupo multicast baseado nos parâmetros do descritor.

udp_multicast_sender.c

Na função UDP_Multicast_Sender_Init é verificado se o contexto foi iniciado, o socket é configurado como UDP e é habilitado o envio no modo multicast

Na função UDP_Multicast_Sender_Send é declarada algumas variáveis para auxiliar na comunicação com o servidor, sendo uma variável booleana que representa o estado de envio para o servidor, uma estrutura sockaddr_in que é usada para configurar o servidor no qual será enviado as mensagens e uma variável de quantidade de dados enviados.

A estrutura é parametrizada com os dados do servidor

Realiza o envio da mensagem para o canal multicast

Aplicação é composta por três executáveis sendo eles:

  • launch_processes – é responsável por lançar os processos button_process e led_process através da combinação fork e exec
  • button_interface – é responsável por ler o GPIO em modo de leitura da Raspberry Pi e escrever o estado interno no arquivo
  • led_interface – é responsável por ler do arquivo o estado interno do botão e aplicar em um GPIO configurado como saída

launch_processes

No main é criada duas variáveis para armazenar o PID do button_process e do led_process, e mais duas variáveis para armazenar o resultado caso o exec venha a falhar.

Em seguida é criado um processo clone, se processo clone for igual a 0, é criado um array de strings com o nome do programa que será usado pelo exec, em caso o exec retorne, o estado do retorno é capturado e será impresso no stdout e aborta a aplicação. Se o exec for executado com sucesso o programa button_process será carregado.

O mesmo procedimento é repetido novamente, porém com a intenção de carregar o led_process.

button_interface

É definida uma lista de comandos que para o envio

A implementação do Button_Run ficou simples, onde é realizada a inicialização do interface de botão e fica em loop aguardando o pressionamento do botão para alterar o estado da variável e enviar a mensagem para o canal multicast

led_interface

A implementação do LED_Run ficou simplificada, é realizada a inicialização da interface de LED, do servidor e fica em loop aguardando o recebimento de uma mensagem.

button_process

A parametrização do cliente fica por conta do processo de botão que inicializa o contexto com o endereço multicast, o serviço e assim os argumentos são passados para Button_Run iniciar o processo.

led_process

A parametrização do servidor fica por conta do processo de LED que inicializa o contexto com o buffer, seu tamanho, a porta do serviço que vai consumir e o callback preenchido, e assim os argumentos são passados para LED_Run iniciar o serviço.

A implementação no evento de recebimento da mensagem, compara a mensagem recebida com os comandos internos para o acionamento do LED, caso for igual executa a ação correspondente.

Compilando, Executando e Matando os processos

Para compilar e testar o projeto é necessário instalar a biblioteca de hardware necessária para resolver as dependências de configuração de GPIO da Raspberry Pi.

Compilando

Para facilitar a execução do exemplo, o exemplo proposto foi criado baseado em uma interface, onde é possível selecionar se usará o hardware da Raspberry Pi 3, ou se a interação com o exemplo vai ser através de input feito por FIFO e o output visualizado através de LOG.

Clonando o projeto

Pra obter uma cópia do projeto execute os comandos a seguir:

Selecionando o modo

Para selecionar o modo é necessário passar para o cmake uma variável de ambiente chamada de ARCH, e pode-se passar os seguintes valores, PC ou RASPBERRY, para o caso de PC o exemplo terá sua interface preenchida com os sources presentes na pasta src/platform/pc, que permite a interação com o exemplo através de FIFO e LOG, caso seja RASPBERRY usará os GPIO’s descritos no artigo.

Modo PC

Modo RASPBERRY

Executando

Para executar a aplicação execute o processo launch_processes para lançar os processos button_process e led_process que foram determinados de acordo com o modo selecionado.

Uma vez executado podemos verificar se os processos estão rodando atráves do comando

O output

Interagindo com o exemplo

Dependendo do modo de compilação selecionado a interação com o exemplo acontece de forma diferente

MODO PC

Para o modo PC, precisamos abrir um terminal e monitorar os LOG’s

Dessa forma o terminal irá apresentar somente os LOG’s referente ao exemplo.

Para simular o botão, o processo em modo PC cria uma FIFO para permitir enviar comandos para a aplicação, dessa forma todas as vezes que for enviado o número 0 irá logar no terminal onde foi configurado para o monitoramento, segue o exemplo

Output do LOG quando enviado o comando algumas vezes

MODO RASPBERRY

Para o modo RASPBERRY a cada vez que o botão for pressionado irá alternar o estado do LED.

Monitorando o tráfego usando o tcpdump

Para monitorar as mensagens que trafegam, é necessário ler uma interface que corresponde ao endereço multicast, para saber quais interfaces que o computador possui é utilizado o comando:

Output

Como é possível ver existem diversos grupos multicast disponíveis, no caso dessa máquina em questão podemos verificar que existe o endereço do grupo selecionado para a aplicação na inteface enp0s31f6 com o endereço 239.192.1.1

O tcpdump possui opções que permite a visualização dos dados, não irei explicar tudo, fica de estudo para quem quiser saber mais sobre a ferramenta. Executando o comando podemos ver todas as mensagens de multicast

Após executar o comando o tcpdump ficará fazendo sniffing da interface, tudo o que for trafegado nessa interface será apresentado, dessa forma enviando um comando e é possível ver a seguinte saída:

  • No instante 08:21:58.903735 IP 192.168.0.140.38455 > 239.192.1.1.1234 o cliente envia uma mensagem para o servidor via multicast

Testando conexão com o servidor via netcat

A aplicação realiza a comunicação entre processos locais, para testar uma comunicação remota é usado o netcat que permite se conectar de forma prática ao servidor e enviar os comandos. Para se conectar basta usar o seguinte comando:

Como descrito no comando netstat é usado o ip de multicast apresentado na interface enp0s31f6 que é o IP 239.192.1.1, então o comando fica

É enviado o comando LED ON, se visualizar no log irá apresentar que o comando foi executado, para monitorar com o tcpdump basta mudar a interface

Matando os processos

Para matar os processos criados execute o script kill_process.sh

Conclusão

O multicast é uma boa solução para enviar mensagens de uma única vez para os interessados, diferente do broadcast somente os registrados irão receber as mensagens, evitando assim o congestionamento do tráfego, essa forma de envio se assemelha ao padrão arquitetural publish–subscribe como por exemplo o MQTT.

Referência

Outros artigos da série

<< UDP BroadcastSocketpair >>
Notificações
Notificar
guest
0 Comentários
Inline Feedbacks
View all comments

WEBINAR

Visão Computacional para a redução de erros em processos manuais

DATA: 23/09 ÀS 17:00 H