stm32 lwip的DHCP
阿新 • • 發佈:2019-01-29
stm32f107 lwip dhcp
第一篇 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
}
第一篇 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
}