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).

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>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];
…
}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;
}
});
}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());
}
}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);
}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");
}
}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");
}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");
}
}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
}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:
- 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.
- 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.