IPv4 Internet Protocol: Extraindo informações em Java

Veja neste artigo como extrair informações importantes apenas com o número do IP fornecido pelo usuário pelo IPv4(Internet Protocol) em Java.

A sigla IP, que significa Internet Protocol ou Protocolo de Internet, é um identificador de um dispositivo em uma rede local ou pública, e neste artigo estudaremos a extração de informações dado um número de IP qualquer.

Um número de IP contém diversas informações que podem ser obtidas através de vários cálculos, tais como: Máscara, Rede, Classe e etc. O objetivo deste artigo é demonstrar como realizar a extração dessas informações em Java e mostrar ao usuário de uma forma amigável e rápida. Principalmente para quem esta cursando matérias relacionadas a Rede de Computadores, na Universidade, este será um programa muito bem-vindo.

Desenvolvimento da Interface (GUI)

O artigo em questão é focado na linguagem Java e estamos partindo do princípio que você, caro leitor, conhece as teorias básicas de Rede de Computadores (Máscaras, Rede, Broadcast, Classes de IP e etc.) pois não entraremos nesses méritos que fugiria do foco do artigo.

Primeiro veja como ficará nossa interface (Figura 1).

Figura 1. Interface

O que temos acima é um Jframe que possui um campo para inserção do número IP e outro campo para mostrar o resultado das informações extraídas ao usuário. O campo IP está com o valor todo zerado pois usamos um Placeholder afim de não deixar espaços em branco, confundindo o usuário. O processo é simples: O usuário preenche o número de IP clica em processar e nosso programa irá mostrar as informações extraídas dentro do campo Resultado.

Para você que irá construir a interface acima no Netbeans, disponibilizamos Listagem 1 o nosso arquivo Form para que você pode ter a mesma interface como mostrada na Figura 1.

<?xml version="1.0" encoding="UTF-8" ?> <Form version="1.3" type="org.netbeans.modules.form.forminfo.JFrameFormInfo"> <Properties> <Property name="defaultCloseOperation" type="int" value="3"/> </Properties> <SyntheticProperties> <SyntheticProperty name="formSizePolicy" type="int" value="1"/> </SyntheticProperties> <AuxValues> <AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="false"/> <AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/> <AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/> <AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/> <AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/> </AuxValues> <Layout> <DimensionLayout dim="0"> <Group type="103" groupAlignment="0" attributes="0"> <Group type="102" attributes="0"> <EmptySpace max="-2" attributes="0"/> <Group type="103" groupAlignment="0" attributes="0"> <Component id="jScrollPane1" alignment="0" min="-2" pref="364" max="-2" attributes="0"/> <Component id="jFormattedTextFieldIP" alignment="0" min="-2" pref="154" max="-2" attributes="0"/> <Component id="jLabel1" alignment="0" min="-2" max="-2" attributes="0"/> <Component id="jLabel2" alignment="0" min="-2" max="-2" attributes="0"/> <Component id="jButtonProcessar" alignment="0" min="-2" max="-2" attributes="0"/> </Group> <EmptySpace pref="24" max="32767" attributes="0"/> </Group> </Group> </DimensionLayout> <DimensionLayout dim="1"> <Group type="103" groupAlignment="0" attributes="0"> <Group type="102" alignment="0" attributes="0"> <EmptySpace max="-2" attributes="0"/> <Component id="jLabel1" min="-2" max="-2" attributes="0"/> <EmptySpace max="-2" attributes="0"/> <Component id="jFormattedTextFieldIP" min="-2" max="-2" attributes="0"/> <EmptySpace min="-2" pref="20" max="-2" attributes="0"/> <Component id="jLabel2" min="-2" max="-2" attributes="0"/> <EmptySpace max="-2" attributes="0"/> <Component id="jScrollPane1" min="-2" pref="116" max="-2" attributes="0"/> <EmptySpace min="-2" pref="14" max="-2" attributes="0"/> <Component id="jButtonProcessar" min="-2" max="-2" attributes="0"/> <EmptySpace max="32767" attributes="0"/> </Group> </Group> </DimensionLayout> </Layout> <SubComponents> <Component class="javax.swing.JLabel" name="jLabel1"> <Properties> <Property name="text" type="java.lang.String" value="IP"/> </Properties> </Component> <Component class="javax.swing.JFormattedTextField" name="jFormattedTextFieldIP"> </Component> <Component class="javax.swing.JLabel" name="jLabel2"> <Properties> <Property name="text" type="java.lang.String" value="Resultado"/> </Properties> </Component> <Container class="javax.swing.JScrollPane" name="jScrollPane1"> <AuxValues> <AuxValue name="autoScrollPane" type="java.lang.Boolean" value="true"/> </AuxValues> <Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/> <SubComponents> <Component class="javax.swing.JTextArea" name="jTextAreaResultado"> <Properties> <Property name="columns" type="int" value="20"/> <Property name="rows" type="int" value="5"/> </Properties> </Component> </SubComponents> </Container> <Component class="javax.swing.JButton" name="jButtonProcessar"> <Properties> <Property name="text" type="java.lang.String" value="Processar"/> </Properties> <Events> <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="jButtonProcessarActionPerformed"/> </Events> </Component> </SubComponents> </Form>
Listagem 1. FInfoIP.form

Desenvolvimento da Lógica (Core)

A próxima etapa é começar a definir a lógica do nosso programa. Iremos mostrar passo a passo a construção da nossa lógica e depois uniremos tudo em uma só classe para facilitar a compreensão e aprendizagem. Observe a Listagem 2.

public class FInfoIP extends javax.swing.JFrame { //1 private enum Classe{A,B,C,D,E}; //2 private Classe classeIP; //3 private int[] ip = new int[4]; … }
Listagem 2. Atributos de instância

Logo abaixo da declaração da nossa classe FinfoIP, definimos alguns atributos de instância que irão nos ajudar a construir a lógica mais à frente. Vejamos: No item 1 temos um enum chamado Classe que possui as classes IP possíveis, no item 2 temos um atributo classeIP do tipo Classe (enum definido no item 1) que armazenará a classe à qual o IP digitado pertence e por fim na linha 3 temos um vetor de inteiros que possui quatro posições, onde cada posição armazenará um octeto do endereço de IP. Agora observe a Listagem 3.

public FInfoIP() { initComponents(); jFormattedTextFieldIP.setFormatterFactory(new AbstractFormatterFactory() { @Override public AbstractFormatter getFormatter(JFormattedTextField tf) { try { MaskFormatter mask = new MaskFormatter("#**.#**.#**.#**"); mask.setValidCharacters("0123456789"); mask.setPlaceholderCharacter('0'); return mask; } catch (ParseException e) { // TODO Auto-generated catch block e.printStackTrace(); } return null; } }); }
Listagem 3. Construtor

Nosso construtor acima possui duas seções importantes, onde a primeira é a chamada ao método initComponents() que inicializa toda a interface gráfica do nosso formulário e a segunda seção diz respeito a criação de uma máscara para o campo onde será digitado o IP.

O método setFormatterFactory() recebe como parâmetro a instância da classe AbstractFormatterFactory. O que fizemos foi criar de forma anônima e implementar um comportamento para o método getFormatter(). Dentro do método getFormatter() nós criamos um objeto do tipo MaskFormatter e configuramos os caracteres válidos para a máscara e um placeholderCharacter que é o caractere que será colocado quando não for digitado nada em algum local da máscara, por isso no início todos os valores estão zerados.

A ação de clicar no botão “Processar”, mostrado na Figura 1, irá disparar o método mostrado na Listagem 4.

private void jButtonProcessarActionPerformed(java.awt.event.ActionEvent evt) { try{ jTextAreaResultado.removeAll(); String ipTmp = jFormattedTextFieldIP.getText().trim(); if (ipTmp.replace(".", "").isEmpty()){ JOptionPane.showMessageDialog(this, "Digite um IP válido"); } constroiIpAsArray(ipTmp); extraiClasse(); extraiMascaraRedeEBroadcast(); }catch(Exception e){ e.printStackTrace(); JOptionPane.showMessageDialog(this, e.getMessage()); } }
Listagem 4. Click do Botão Processar

Perceba que circundamos todo nosso código com um block try-catch, dessa forma qualquer erro que ocorrer será mostrado ao usuário. Antes de iniciar qualquer coisa nós limpamos o jTextAreaResultado para garantir que não há nada lá, evitando confusão de informações. No bloco “if” nós checamos se o valor não é vazio, ou seja, se foi digitado algum IP antes de clicar em processar.

Mais adiante temos os métodos que fazem a nossa lógica funcionar, são eles: constroiIpAsArray, extraiClasse, extraiMascaraRedeEBroadcast.

private void constroiIpAsArray(String ipAsString){ String[] ipAsStringArray = ipAsString.split("\\."); for(int i = 0; i < 4; i++){ ip[i] = Integer.parseInt(ipAsStringArray[i].trim()); } addInfo("IP: "+ipAsString); }
Listagem 5. constroiIpAsArray

Quando o usuário digita o IP no campo de texto este IP é uma String com pontos entre os octetos que precisamos, então o método mostrado na Listagem 5 irá extrair os quatro octetos entre os pontos da String e colocar no array de inteiros chamado ip que declaramos na Listagem 2. Trabalhar com os quatro octetos separados por um vetor e em inteiros torna-se muito mais fácil do que trabalhar direto com String.

private void extraiClasse(){ if (ip[0] >= 1 && ip[0] <= 127){ addInfo("Classe: A"); classeIP = Classe.A; }else if (ip[0] >= 128 && ip[0] <= 191){ addInfo("Classe: B"); classeIP = Classe.B; }else if (ip[0] >= 192 && ip[0] <= 223){ addInfo("Classe: C"); classeIP = Classe.C; }else if (ip[0] >= 224 && ip[0] <= 239){ addInfo("Classe: D [Reservado para Multicast]"); classeIP = Classe.D; }else if (ip[0] >= 240 && ip[0] <= 255){ addInfo("Classe: E [Reservado para pesquisas]"); classeIP = Classe.E; }else{ JOptionPane.showMessageDialog(this, "O IP digitado é inválido, pois não possui nenhum classe"); throw new RuntimeException("O IP digitado é inválido, pois não possui nenhum classe"); } }
Listagem 6. extraiClasse

De posse dos quatro octetos separados por um vetor de inteiros, fica simples identificar a classe do IP digitado. O que nós fazemos é pegar o primeiro octeto (int[0]) e checar qual o range dele, ou seja, entre que valores ele se encontra. As classes só podem ser: A, B, C, D, E então o primeiro octeto digitado não esteja em nenhuma dessas classes o IP é inválido e o programa não pode continuar executando a lógica.

Ainda na Listagem 6 toda vez que encontramos a classe para o IP digitado nós atribuímos um valor do enum Classe para o atributo classeIP, pois iremos usá-lo mais à frente.

O método addInfo() que estamos utilizando com constância é apenas um auxiliar para evitar código repetido, como mostra a Listagem 7.

private void addInfo(String info){ jTextAreaResultado.append(info + "\n"); }
Listagem 7. addInfo

Evitamos assim ficar digitando a toda hora o append(...), além de usarmos o conceito de encapsulamento.

private void extraiMascaraRedeEBroadcast(){ if (classeIP.equals(Classe.A)){ addInfo("Máscara: 255.0.0.0"); addInfo("Rede: "+ip[0]+".0.0.0"); addInfo("Broadcast: "+ip[0]+".255.255.255"); }else if (classeIP.equals(Classe.B)){ addInfo("Máscara: 255.255.0.0"); addInfo("Rede: "+ip[0]+"."+ip[1]+".0.0"); addInfo("Broadcast: "+ip[0]+"."+ip[1]+".255.255"); }else if (classeIP.equals(Classe.C)){ addInfo("Máscara: 255.255.255.0"); addInfo("Rede: "+ip[0]+"."+ip[1]+"."+ip[2]+".0"); addInfo("Broadcast: "+ip[0]+"."+ip[1]+"."+ip[2]+".255"); } }
Listagem 8. extraiMascaraRedeEBroadcast

Por fim, na Listagem 8 nós verificamos qual foi a classe de IP encontrada e adicionamos as informações de Máscara, Rede e Broadcast. Perceba que aqui fazemos uso dos três octetos, se necessário.

import java.text.ParseException; import javax.swing.JFormattedTextField; import javax.swing.JFormattedTextField.AbstractFormatter; import javax.swing.JFormattedTextField.AbstractFormatterFactory; import javax.swing.JOptionPane; import javax.swing.text.MaskFormatter; public class FInfoIP extends javax.swing.JFrame { private enum Classe{A,B,C,D,E}; private Classe classeIP; private int[] ip = new int[4]; /** Creates new form FInfoIP */ public FInfoIP() { initComponents(); jFormattedTextFieldIP.setFormatterFactory(new AbstractFormatterFactory() { @Override public AbstractFormatter getFormatter(JFormattedTextField tf) { try { MaskFormatter mask = new MaskFormatter("#**.#**.#**.#**"); mask.setValidCharacters("0123456789"); mask.setPlaceholderCharacter('0'); return mask; } catch (ParseException e) { // TODO Auto-generated catch block e.printStackTrace(); } return null; } }); } /** This method is called from within the constructor to * initialize the form. * WARNING: Do NOT modify this code. The content of this method is * always regenerated by the Form Editor. */ // <editor-fold defaultstate="collapsed" desc=" Código Gerado " >//GEN-BEGIN:initComponents private void initComponents() { jLabel1 = new javax.swing.JLabel(); jFormattedTextFieldIP = new javax.swing.JFormattedTextField(); jLabel2 = new javax.swing.JLabel(); jScrollPane1 = new javax.swing.JScrollPane(); jTextAreaResultado = new javax.swing.JTextArea(); jButtonProcessar = new javax.swing.JButton(); setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE); jLabel1.setText("IP"); jLabel2.setText("Resultado"); jTextAreaResultado.setColumns(20); jTextAreaResultado.setRows(5); jScrollPane1.setViewportView(jTextAreaResultado); jButtonProcessar.setText("Processar"); jButtonProcessar.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { jButtonProcessarActionPerformed(evt); } }); javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane()); getContentPane().setLayout(layout); layout.setHorizontalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createSequentialGroup() .addContainerGap() .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 364, javax.swing.GroupLayout.PREFERRED_SIZE) .addComponent(jFormattedTextFieldIP, javax.swing.GroupLayout.PREFERRED_SIZE, 154, javax.swing.GroupLayout.PREFERRED_SIZE) .addComponent(jLabel1) .addComponent(jLabel2) .addComponent(jButtonProcessar)) .addContainerGap(24, Short.MAX_VALUE)) ); layout.setVerticalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createSequentialGroup() .addContainerGap() .addComponent(jLabel1) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(jFormattedTextFieldIP, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) .addGap(20, 20, 20) .addComponent(jLabel2) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 116, javax.swing.GroupLayout.PREFERRED_SIZE) .addGap(14, 14, 14) .addComponent(jButtonProcessar) .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) ); pack(); }// </editor-fold>//GEN-END:initComponents private void jButtonProcessarActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButtonProcessarActionPerformed try{ jTextAreaResultado.removeAll(); String ipTmp = jFormattedTextFieldIP.getText().trim(); if (ipTmp.replace(".", "").isEmpty()){ JOptionPane.showMessageDialog(this, "Digite um IP válido"); } constroiIpAsArray(ipTmp); extraiClasse(); extraiMascaraRedeEBroadcast(); }catch(Exception e){ e.printStackTrace(); JOptionPane.showMessageDialog(this, e.getMessage()); } }//GEN-LAST:event_jButtonProcessarActionPerformed private void constroiIpAsArray(String ipAsString){ String[] ipAsStringArray = ipAsString.split("\\."); for(int i = 0; i < 4; i++){ ip[i] = Integer.parseInt(ipAsStringArray[i].trim()); } addInfo("IP: "+ipAsString); } private void extraiClasse(){ if (ip[0] >= 1 && ip[0] <= 127){ addInfo("Classe: A"); classeIP = Classe.A; }else if (ip[0] >= 128 && ip[0] <= 191){ addInfo("Classe: B"); classeIP = Classe.B; }else if (ip[0] >= 192 && ip[0] <= 223){ addInfo("Classe: C"); classeIP = Classe.C; }else if (ip[0] >= 224 && ip[0] <= 239){ addInfo("Classe: D [Reservado para Multicast]"); classeIP = Classe.D; }else if (ip[0] >= 240 && ip[0] <= 255){ addInfo("Classe: E [Reservado para pesquisas]"); classeIP = Classe.E; }else{ JOptionPane.showMessageDialog(this, "O IP digitado é inválido, pois não possui nenhum classe"); throw new RuntimeException("O IP digitado é inválido, pois não possui nenhum classe"); } } private void extraiMascaraRedeEBroadcast(){ if (classeIP.equals(Classe.A)){ addInfo("Máscara: 255.0.0.0"); addInfo("Rede: "+ip[0]+".0.0.0"); addInfo("Broadcast: "+ip[0]+".255.255.255"); }else if (classeIP.equals(Classe.B)){ addInfo("Máscara: 255.255.0.0"); addInfo("Rede: "+ip[0]+"."+ip[1]+".0.0"); addInfo("Broadcast: "+ip[0]+"."+ip[1]+".255.255"); }else if (classeIP.equals(Classe.C)){ addInfo("Máscara: 255.255.255.0"); addInfo("Rede: "+ip[0]+"."+ip[1]+"."+ip[2]+".0"); addInfo("Broadcast: "+ip[0]+"."+ip[1]+"."+ip[2]+".255"); } } private void addInfo(String info){ jTextAreaResultado.append(info + "\n"); } /** * @param args the command line arguments */ public static void main(String args[]) { java.awt.EventQueue.invokeLater(new Runnable() { public void run() { new FInfoIP().setVisible(true); } }); } // Declaração de variáveis - não modifique//GEN-BEGIN:variables private javax.swing.JButton jButtonProcessar; private javax.swing.JFormattedTextField jFormattedTextFieldIP; private javax.swing.JLabel jLabel1; private javax.swing.JLabel jLabel2; private javax.swing.JScrollPane jScrollPane1; private javax.swing.JTextArea jTextAreaResultado; // Fim da declaração de variáveis//GEN-END:variables }
Listagem 9. FinfoIP.java completo

A Listagem 9 possui a implementação completa de todos os métodos explicados nas seções acima. Com ela você poderá treinar e testar a lógica ministrada.

Proposta de Atividade

Dado o desenvolvimento do programa proposto é perceptível que o mesmo pode e deve sofrer algumas melhorias para tornar-se ainda mais útil. Propomos a você, caro leitor, o desenvolvimento dessas melhorias como forma de praticar e aperfeiçoar suas habilidades. Vejamos a lista de melhorias propostas:

  1. Possibilitar que cada octeto do endereço IP possa ser digitado de forma independente, possibilitando o uso da tecla TAB para “pular” entre octetos. Dica: Usar vários campos de texto, um para cada octeto.
  2. Possibilitar que o usuário informe uma máscara de sub-rede customizada (ex: 255.255.255.240), dessa forma o cálculo para obter as outras informações irá mudar. Dica: Utilizar a classe BitSet para realizar operações lógicas entre a máscara e o IP para obter informações pertinentes ao usuário.

Com este artigo foi possível aprender um pouco mais sobre a linguagem Java, aplicada a problemas reais, usando técnicas como: Enumeração, Máscara de Valores, Vetorização de valores e etc. Além disso, propomos a implementação de melhorias no programa proposta, afim de aperfeiçoar as habilidades do leitor e forçando o mesmo a praticar as listagens demonstradas.

Artigos relacionados