STM32
直播中

刘超

7年用户 1405经验值
私信 关注
[问答]

如何去实现DHCP的自动获取功能呢

如何去实现DHCP的自动获取功能呢?
DHCP获取IP的简单过程是怎样的?

回帖(1)

白桦

2021-11-2 11:39:23
  第一篇 DHCP自动获取功能的实现
  DHCP在电脑中经常用到,因为我们并不关心我们电脑的IP是多少 只要能连上网络就行了。在嵌入式的产品设备中,DHCP用到的比较少,因为很多的操作是通过ip来进行的。除非那种有服务器的系统设备会用到。这里我们只能简单说一下流程,设计的代码太多了,具体的需要学习者自己去慢慢研究。
  dhcp模块:
  dhcp模块用于获取设备ip地址的相关信息。其处理入口主要有这么几个dpch的启动、dpch的接收报文处理以及定时器模块的处理。
  主要的接口原型如下:
  err_t dhcp_start(struct netif *netif)
  该接口用于设备启动dhcp模块,主要是客户端的功能。该模块实现设备dhcp描述结构生成,并将dhcp的端口绑定到udp协议中,以及将本dhcp模块跟远端服务器端口进行绑定。最后启动dhcp申请。
  static void dhcp_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, struct ip_addr *addr, u16_t port)
  该接口为一个注册接口,用于dhcp报文接收。在start dhcp时,该接口通过dhcp的udp pcb注册到udp协议层。Udp进行报文处理后,根据端口调用该注册接口。该接口中,实现dhcp报文的协议处理。
  Void dhcp_fine_tmr()
  Void dhcp_coarse_tmr()
  这两个函数接口实现了dhcp的相关超时处理监控。上面一个用于请求应答超时处理。下面一个用于地址租用情况的到期处理。
  从源码分析看,上述的接口在应用lwip的协议栈时,需要重点关注。对于小内存应用的场合,该协议栈的内存管理以及pbuf应用部分需要自行改写。
  打开工程《科星F107开发板网络应用篇之DHCP自动获取功能》
  进入主函数
  int main(void)
  {
  System_Setup();
  LwIP_Init();
  while (1)
  {
  /* Periodic tasks */
  System_Periodic_Handle();
  }
  }
  主要看一下 DHCP和静态的时候配置有哪些不同
  进入函数LwIP_Init();
  void LwIP_Init(void)
  {
  struct ip_addr ipaddr;
  struct ip_addr netmask;
  struct ip_addr gw;
  uint8_t macaddress[6]={0,0,0,0,0,1};
  mem_init();
  memp_init();
  ipaddr.addr = 0;
  netmask.addr = 0;
  gw.addr = 0;
  IP 网关 子网掩码 我们设置为0,就是没有值。需要我们自动获取到。
  Set_MAC_Address(macaddress);设置MAC地址,这个不管任何时候都要设置。
  //创建一个网络接口
  netif_add(&netif, &ipaddr, &netmask, &gw, NULL, ðernetif_init, ðernet_input);
  netif_set_default(&netif);
  dhcp_start(&netif);主要是这句,这一句就开始了自动获取的进程,以2,4,8,16秒为间隔,加上1-1000毫秒之间随机长度的时间
  netif_set_up(&netif);
  }
  DHCP获取IP的简单过程
  当DHCP客户机第一次登录网络的时候(也就是客户机上没有任何IP地址数据时),它会通过UDP 67端口向网络上发出一个DHCPDISCOVER数据包(包中包含客户机的MAC地址和计算机名等信息)。因为客户机还不知道自己属于哪一个网络,所以封包的源地址为0.0.0.0,目标地址为255.255.255.255,然后再附上DHCP discover的信息,向网络进行广播。
  DHCP discover的等待时间预设为1秒,也就是当客户机将第一个DHCP discover封包送出去之后,在1秒之内没有得到回应的话,就会进行第二次DHCP discover广播。若一直没有得到回应,客户机会将这一广播包重新发送四次(以2,4,8,16秒为间隔,加上1-1000毫秒之间随机长度的时间)。
  执行完dhcp_start(&netif);这个函数,开发板就开始和所接的路由器获取IP的进程。
  那么我们程序怎么知道是否获取到了没有呢 接着看函数
  System_Periodic_Handle();
  进入
  void System_Periodic_Handle(void)
  {
  GET_DHCP_IP(LocalTime);
  LwIP_Periodic_Handle(LocalTime);
  }
  进入函数GET_DHCP_IP(LocalTime);
  void GET_DHCP_IP(__IO uint32_t localtime)
  {
  struct ip_addr ipaddr;
  struct ip_addr netmask;
  struct ip_addr gw;
  /* 250 ms */
  if (localtime - DisplayTimer 》= GET_DHCP_MSECS) 每250ms检测一次是否得到IP
  {
  DisplayTimer = localtime;
  /* We have got a new IP address so update the display */
  if (IPaddress != netif.ip_addr.addr)
  {
  __IO uint8_t iptab[4];
  /* Read the new IP address */
  IPaddress = netif.ip_addr.addr;
  iptab[0] = (uint8_t)(IPaddress 》》 24);
  iptab[1] = (uint8_t)(IPaddress 》》 16);
  iptab[2] = (uint8_t)(IPaddress 》》 8);
  iptab[3] = (uint8_t)(IPaddress);
  if (netif.flags & NETIF_FLAG_DHCP)如果得到IP的话 建立端口连接
  {
  iptab[0] = (uint8_t)(IPaddress 》》 24);
  iptab[1] = (uint8_t)(IPaddress 》》 16);
  iptab[2] = (uint8_t)(IPaddress 》》 8);
  iptab[3] = (uint8_t)(IPaddress);
  server_init();初始化UDP端口,其实到这里DHCP已经成功了 这里初始化这个端口 是为了增加UDP扫描,以便我们能知道得到的ip是什么。这个函数 还有扫描的功能就不在讲了 前面刚刚讲过。可以自己点进去看一下程序。
  }
  }
  else if (IPaddress == 0)
  {
  if (netif.dhcp-》tries 》 MAX_DHCP_TRIES) 如果是超时进入超时处理
  {
  struct ip_addr ipaddr;
  struct ip_addr netmask;
  struct ip_addr gw
  dhcp_stop(&netif);
  IP4_ADDR(&ipaddr, 192, 168, 1, 8);
  IP4_ADDR(&netmask, 255, 255, 255, 0);
  IP4_ADDR(&gw, 192, 168, 1, 1);
  netif_set_addr(&netif, &ipaddr , &netmask, &gw);
  }
  }
  }
  上面的函数主要是检测是不是获取到IP
  再看另一个主函数LwIP_Periodic_Handle(LocalTime);
  进入 主要看和DHCP有关的两个函数
  void LwIP_Periodic_Handle(__IO uint32_t localtime)
  {
  /* TCP periodic process every 250 ms */
  if (localtime - TCPTimer 》= TCP_TMR_INTERVAL)
  {
  TCPTimer = localtime;
  tcp_tmr();
  }
  /* ARP periodic process every 5s */
  if (localtime - ARPTimer 》= ARP_TMR_INTERVAL)
  {
  ARPTimer = localtime;
  etharp_tmr();
  }
  #if LWIP_DHCP
  /* Fine DHCP periodic process every 500ms */
  if (localtime - DHCPfineTimer 》= DHCP_FINE_TIMER_MSECS)
  {
  DHCPfineTimer = localtime;
  dhcp_fine_tmr();请求应答超时处理
  }。
  /* DHCP Coarse periodic process every 60s */
  if (localtime - DHCPcoarseTimer 》= DHCP_COARSE_TIMER_MSECS)
  {
  DHCPcoarseTimer = localtime;
  dhcp_coarse_tmr();地址租用情况的到期处理
  }
  #endif
  }
举报

更多回帖

发帖
×
20
完善资料,
赚取积分