<<返回上一页

从路由器获取动态IP地址


关键词:DHCP  W5500  WIZnet  W5500EVB  动态获取IP


本节中W5500作为DHCP客户端,路由器作为DHCP服务器端。在DHCP请求的过程中,包括4个主要的阶段:发现阶段、提供阶段、选择阶段以及确认阶段。

下面来说一下整个DHCP请求流程。

首先W5500客户端发送DHCP DISCOVER消息(IP地址租用申请),这个消息通过广播方式发出,所有网络中的DHCP服务器都将接收到这个消息。随后,网络中的DHCP服务器会回应一个DHCPOFFER消息(IP地址租用提供),由于这个时候客户端还没有网络地址,所以DHCP OFFER也是通过广播的方式发送出去的。 后,向该服务器发送DHCP REQUEST消息。在DHCP REQUEST消息中将包含客户端然申请的IP地址。最后,DHCP服务器将回送DHCP ACK的响应消息来通知客户端可以使用该IP地址,该确认里面包含了分配的IP地址和该地址的一个稳定期限的租约(默认是8天),并同时更新DHCP数据库。

主循环代码如下:
	while(1)
	{
		DHCP_run();
	}
	
	uint8_t DHCP_run(void)
	{
		uint8_t  type;
		uint8_t  ret;
		if(dhcp_state == STATE_DHCP_STOP) return DHCP_STOPPED;
		if(getSn_SR(SOCK_DHCP) != SOCK_UDP)
		socket(SOCK_DHCP, Sn_MR_UDP, DHCP_CLIENT_PORT, 0x00);
		ret = DHCP_RUNNING;	
		type = parseDHCPMSG();
		switch ( dhcp_state ) 
		{
			case STATE_DHCP_READY :
	        	DHCP_allocated_ip[0] = 0;
	        	DHCP_allocated_ip[1] = 0;
	        	DHCP_allocated_ip[2] = 0;
	        	DHCP_allocated_ip[3] = 0;    
	   			send_DHCP_DISCOVER();
				dhcp_time = 0;
	   			dhcp_state = STATE_DHCP_DISCOVER;
			break;
			case STATE_DHCP_DISCOVER :
				if (type == DHCP_OFFER)
				{
					#ifdef _DHCP_DEBUG_
		    		printf("> Receive DHCP_OFFER\r\n");
					#endif
	        		DHCP_allocated_ip[0] = pDHCPMSG->yiaddr[0];
	        		DHCP_allocated_ip[1] = pDHCPMSG->yiaddr[1];
	        		DHCP_allocated_ip[2] = pDHCPMSG->yiaddr[2];
	        		DHCP_allocated_ip[3] = pDHCPMSG->yiaddr[3];  
					send_DHCP_REQUEST();
					dhcp_time = 0;
					dhcp_state = STATE_DHCP_REQUEST;
		 		} 
					else 
					ret = check_DHCP_timeout();
			break;
			case STATE_DHCP_REQUEST :
				if (type == DHCP_ACK) 
					{
						#ifdef _DHCP_DEBUG_
						printf("> Receive DHCP_ACK\r\n");
						#endif
					if (check_DHCP_leasedIP()) 
					{
						printf("ip:%d.%d.%d.%d\r\n",DHCP_allocated_ip[0],DHCP_allocated_ip[1],DHCP_allocated_ip[2],DHCP_allocated_ip[3]);
		          		printf("sn:%d.%d.%d.%d\r\n",DHCP_allocated_sn[0],DHCP_allocated_sn[1],DHCP_allocated_sn[2],DHCP_allocated_sn[3]);
		          		printf("gw:%d.%d.%d.%d\r\n",DHCP_allocated_gw[0],DHCP_allocated_gw[1],DHCP_allocated_gw[2],DHCP_allocated_gw[3]);
						dhcp_ip_assign();
						reset_DHCP_timeout();
						hcp_state = STATE_DHCP_LEASED;
					} 
					else 
					{
						reset_DHCP_timeout();
						dhcp_ip_conflict();
						dhcp_state = STATE_DHCP_READY;
					}
					} 
					else if (type == DHCP_NAK) 
					{
						#ifdef _DHCP_DEBUG_
						printf("> Receive DHCP_NACK\r\n");
						#endif
						reset_DHCP_timeout();
						dhcp_state = STATE_DHCP_DISCOVER;
				  	} 
					else 
					ret = check_DHCP_timeout();
			break;
			case STATE_DHCP_LEASED :
				ret = DHCP_IP_LEASED;		  
				if ((dhcp_lease_time != DEFAULT_LEASETIME) && ((dhcp_lease_time/2) < dhcp_time))
				{	
					#ifdef _DHCP_DEBUG_
	 				printf("> Maintains the IP address \r\n");
					#endif
					type = 0;
					OLD_allocated_ip[0] = DHCP_allocated_ip[0];
					OLD_allocated_ip[1] = DHCP_allocated_ip[1];
					OLD_allocated_ip[2] = DHCP_allocated_ip[2];
					OLD_allocated_ip[3] = DHCP_allocated_ip[3];	
					DHCP_XID++;
					send_DHCP_REQUEST();				
					reset_DHCP_timeout();
					dhcp_state = STATE_DHCP_REREQUEST;
				}
			break;
			case STATE_DHCP_REREQUEST :
				ret = DHCP_IP_LEASED;
				if (type == DHCP_ACK) 
				{
					dhcp_retry_count = 0;
					if (OLD_allocated_ip[0] != DHCP_allocated_ip[0] || 
					OLD_allocated_ip[1] != DHCP_allocated_ip[1] ||
					OLD_allocated_ip[2] != DHCP_allocated_ip[2] ||
					OLD_allocated_ip[3] != DHCP_allocated_ip[3]) 
				{
					ret = DHCP_IP_CHANGED;
					dhcp_ip_update();
	               	#ifdef _DHCP_DEBUG_
	                printf(">IP changed.\r\n");
	               	#endif					
				}
	         		#ifdef _DHCP_DEBUG_
	           		else printf(">IP is continued.\r\n");
	         		#endif            				
					reset_DHCP_timeout();
					dhcp_state = STATE_DHCP_LEASED;
				} 
				else if (type == DHCP_NAK) 
				{
					#ifdef _DHCP_DEBUG_
					printf("> Receive DHCP_NACK, Failed to maintain ip\r\n");
					#endif
					reset_DHCP_timeout();
					dhcp_state = STATE_DHCP_DISCOVER;
				} 
				else ret = check_DHCP_timeout();
		   	break;
			default :
	   		break;
			}
		return ret;
	}
	
DHCP的测试步骤如下
  1. DHCP例程将动态获取的IP信息配置给W5500,所以在w5500_conf.c文件中设置ip_from为IP_FROM_DHCP。
  2. 对代码进行编译,之后将程序烧录到野火开发板。
  3. 连接好网线,USB串口线。打开串口调试工具,复位野火开发板,从输出结果可以得到图1设置信息。
  4. 在Windows下的具体操作是,开始→运行→(键入)cmd,输入 ping 192.168.1.109→回车,看到回复信息如图2所示。可以成功ping到通过DHCP动态获取分配给W5500的IP地址,可以看到整个过程是如此的简单。

图1:DHCP动态获取信息

图2:ping DHCP 获取IP地址


例程下载:【DHCP】
编译环境:keil V5.11
硬件要求:W5500EVB