java实现通过DHCP协议获取IP地址

前言

DHCP(Dynamic Host Configuration Protocol),动态主机配置协议,是一个应用层协议。当我们将客户主机IP地址设置为动态获取方式时,DHCP服务器就会根据DHCP协议给客户端分配IP,使得客户端机器能够利用这个IP上网。我们的电脑和手机使用WIFI的时候,都是使用DHCP协议来获取IP的。

ipconfig /all

windows系统下,我们可以使用上面的命令查看IP的获取方式和DHCP服务器地址。

分配原理

  1. DHCP客户端以广播的方式发出Discover报文。
  2. 所有的DHCP服务器都能够接收到此报文,都会给出响应,向客户端发送一个Offer报文。该报文中包含提供给客户端使用的IP地址,也包含服务器自己的IP地址,以便客户端区分不同的服务器。服务器在发出此报文后会保存一个已分配IP地址的纪录。
  3. 客户端只能处理其中的一个Offer报文,一般的原则是处理最先收到的报文。客户端再次以广播的方式发出Request报文,会包含选中的服务器的IP地址和需要的IP地址。
  4. 服务器收到Request报文后,判断其中服务器的IP地址是否与自己的地址相同。如果不相同,不做任何处理只清除相应IP地址分配记录,如果相同,就会向客户端响应一个ACK报文,其中会包含IP地址的使用租期信息(可以参考上面ipconfig命令的结果)。
  5. 客户端接收到ACK报文后,检查服务器分配的IP地址是否能够使用。如果可以使用,则客户端成功获得IP地址并根据IP地址使用租期自动启动续延过程,如果发现分配的IP地址已经被使用,则向服务器发出Decline报文,通知服务器禁用这个IP地址,然后客户端开始新的IP申请过程。
  6. 客户端在成功获取IP地址后,随时可以通过发送Release报文释放自己的IP地址,服务器收到Release报文后,会回收相应的IP地址并重新分配。

更多工作原理相关,查看DHCP百度百科

代码实现

maven依赖

<dependency>
  <groupId>com.helger</groupId>
  <artifactId>dhcp4java</artifactId>
  <version>1.1.0</version>
</dependency>
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import org.dhcp4java.DHCPConstants;
import org.dhcp4java.DHCPPacket;
import org.dhcp4java.HardwareAddress;

public class DHCPTest {

  public static void main(String[] args) throws IOException {

    //当前电脑的物理地址
    byte[] macAddress = HardwareAddress.getHardwareAddressByString("5C:80:B6:FD:91:A7")
        .getHardwareAddress();
    //封装DHCP请求包
    DHCPPacket discover = new DHCPPacket();
    //发送DISCOVER报文
    discover.setOp(DHCPConstants.DHCPDISCOVER);
    //硬件类别为以太网
    discover.setHtype(DHCPConstants.HTYPE_ETHER);
    //硬件地址长度 以太网为6
    discover.setHlen((byte) 6);
    //局域网为0
    discover.setHops((byte) 0);
    //请求ID
    discover.setXid(123);
    //客户端启动时间(秒)
    discover.setSecs((short) 10000);
    discover.setFlags((short) 0);
    //客户端的硬件地址
    discover.setChaddr(macAddress);
    //消息类型
    discover.setDHCPMessageType(DHCPConstants.DHCPDISCOVER);
    //客户端请求服务器的68端口,服务器请求客户端的67端口
    DatagramSocket socket = new DatagramSocket(DHCPConstants.BOOTP_REPLY_PORT);
    byte[] discoverBytes = discover.serialize();
    DatagramPacket sendPacket = new DatagramPacket(discoverBytes,
        discoverBytes.length,
        InetAddress.getByName("255.255.255.255"), DHCPConstants.BOOTP_REQUEST_PORT);
    //发送请求报文
    socket.send(sendPacket);
    DatagramPacket receivePacket = new DatagramPacket(new byte[1500], 1500);
    //接收服务器的响应报文
    socket.receive(receivePacket);
    DHCPPacket resultDhcpPacket = DHCPPacket.getPacket(receivePacket);
    //返回报文包含macAddress
    if (bytesToHexString(resultDhcpPacket.getChaddr()).contains(
        bytesToHexString(macAddress))) {
      //获取的IP地址
      System.out.println(resultDhcpPacket.getYiaddr());//192.168.0.142
    }
    socket.close();
  }

  private static String bytesToHexString(byte[] src) {
    StringBuilder stringBuilder = new StringBuilder();
    for (byte b : src) {
      int v = b & 0xFF;
      String hv = Integer.toHexString(v);
      if (hv.length() < 2) {
        stringBuilder.append(0);
      }
      stringBuilder.append(hv);
    }
    return stringBuilder.toString();
  }

}

查看当前电脑的物理地址,5C:80:B6:FD:91:A7

参考

DHCP百度百科
java实现DHCP协议获取ip地址
java 探测网络中是否有dhcp环境
Wireshark分析DHCP

posted @ 2022-03-19 22:48  strongmore  阅读(1501)  评论(0编辑  收藏  举报