前言
DHCP(Dynamic Host Configuration Protocol),動態主機配置協議,是一個應用層協議。當我們將客戶主機IP地址設置為動態獲取方式時,DHCP服務器就會根據DHCP協議給客戶端分配IP,使得客戶端機器能夠利用這個IP上網。我們的電腦和手機使用WIFI的時候,都是使用DHCP協議來獲取IP的。
ipconfig /all
windows系統下,我們可以使用上面的命令查看IP的獲取方式和DHCP服務器地址。

分配原理
- DHCP客戶端以廣播的方式發出Discover報文。
- 所有的DHCP服務器都能夠接收到此報文,都會給出響應,向客戶端發送一個Offer報文。該報文中包含提供給客戶端使用的IP地址,也包含服務器自己的IP地址,以便客戶端區分不同的服務器。服務器在發出此報文后會保存一個已分配IP地址的紀錄。
- 客戶端只能處理其中的一個Offer報文,一般的原則是處理最先收到的報文。客戶端再次以廣播的方式發出Request報文,會包含選中的服務器的IP地址和需要的IP地址。
- 服務器收到Request報文后,判斷其中服務器的IP地址是否與自己的地址相同。如果不相同,不做任何處理只清除相應IP地址分配記錄,如果相同,就會向客戶端響應一個ACK報文,其中會包含IP地址的使用租期信息(可以參考上面ipconfig命令的結果)。
- 客戶端接收到ACK報文后,檢查服務器分配的IP地址是否能夠使用。如果可以使用,則客戶端成功獲得IP地址並根據IP地址使用租期自動啟動續延過程,如果發現分配的IP地址已經被使用,則向服務器發出Decline報文,通知服務器禁用這個IP地址,然后客戶端開始新的IP申請過程。
- 客戶端在成功獲取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