LWIP网络协议栈DHCP移植

4.6 新建lwip_config.c文件

在LWIP/app目录下新建一个lwip_config.c/lwip_config.h文件。用于编写动态IP地址分配处理代码,和LWIP事物轮询、初始化代码。

 

编写一个LWIP初始化配置函数,向LWIP协议栈添加一个新的网卡设备

 

/*

函数功能: LWIP协议栈初始化

*/

void lwip_config_init(void)

{

ip_addr_t ipaddr;   //IP地址

ip_addr_t netmask;  //子网掩码

ip_addr_t gw;       //网关

 

//全部初始化为0  -因为使用了动态IP地址分配

ipaddr.addr=0;

netmask.addr=0;

gw.addr=0;

 

/*1. 初始化LWIP内核*/

lwip_init();

/*2. 向网卡列表中添加一个网络设备*/

netif_add(&lwip_netif,&ipaddr,&netmask,&gw,NULL,ðernetif_init,ðernet_input);

/*3. 开启DHCP服务 */

dhcp_start(&lwip_netif);

/*4. 设置netif为默认网口*/

netif_set_default(&lwip_netif);

/*5. 打开netif网口*/

netif_set_up(&lwip_netif);

编写LWIP事物轮询函数与DHCP处理函数 

u32 TCPTimer=0; //TCP查询计时器

u32 ARPTimer=0; //ARP查询计时器

u32 DHCPfineTimer=0;   //DHCP精细处理计时器

u32 DHCPcoarseTimer=0;  //DHCP粗糙处理计时器

u32 DHCP_State=1;          //保存DHCP状态 1表示没有分配成功 0表示分配成功

 

/*

函数功能:  LWIP轮询任务

*/

void lwip_periodic_handle()

{

//每250ms调用一次tcp_tmr()函数

if(TCPTimer >= TCP_TMR_INTERVAL)

{

TCPTimer=0;

tcp_tmr();  //处理TCP协议请求

}

 

//ARP每5s周期性调用一次

if(ARPTimer >= ARP_TMR_INTERVAL)

{

ARPTimer=0;

etharp_tmr();

}

//每500ms调用一次dhcp_fine_tmr()

if(DHCPfineTimer >= DHCP_FINE_TIMER_MSECS)

{

DHCPfineTimer=0;

dhcp_fine_tmr(); //动态IP地址分配的事物处理

if(DHCP_State)lwip_dhcp_process_handle();  //DHCP处理

}

 

//每60s执行一次DHCP粗糙处理

if(DHCPcoarseTimer >= DHCP_COARSE_TIMER_MSECS)

{

DHCPcoarseTimer=0;

dhcp_coarse_tmr();

}  

}

 

//lwip控制结构体

typedef struct  

{

u8 remoteip[4]; //服务器主机IP地址 

u8 ip[4];        //本机IP地址

u8 netmask[4];  //子网掩码

u8 gateway[4];  //默认网关的IP地址

}__lwip_dev;

 

extern __lwip_dev lwipdev; //lwip信息结构体

 

__lwip_dev lwipdev; //lwip信息结构体

 

 

/*

函数功能: DHCP处理任务

*/

void lwip_dhcp_process_handle(void)

{

u32 ip=0,netmask=0,gw=0;

ip=lwip_netif.ip_addr.addr; //读取新IP地址

netmask=lwip_netif.netmask.addr;   //读取子网掩码

gw=lwip_netif.gw.addr;           //读取默认网关

 

if(ip!=0) //正确获取到IP地址的时候

{

DHCP_State=0; //表示分配成功

  //解析出通过DHCP获取到的IP地址

lwipdev.ip[3]=(uint8_t)(ip>>24); 

lwipdev.ip[2]=(uint8_t)(ip>>16);

lwipdev.ip[1]=(uint8_t)(ip>>8);

lwipdev.ip[0]=(uint8_t)(ip);

printf("动态分配

IP:..............%d.%d.%d.%drn",lwipdev.ip[0],lwipdev.ip[1],lwipdev.ip[2],lwipdev.ip[3]);

//解析通过DHCP获取到的子网掩码地址

lwipdev.netmask[3]=(uint8_t)(netmask>>24);

lwipdev.netmask[2]=(uint8_t)(netmask>>16);

lwipdev.netmask[1]=(uint8_t)(netmask>>8);

lwipdev.netmask[0]=(uint8_t)(netmask);

printf("子网掩

码............%d.%d.%d.%drn",lwipdev.netmask[0],lwipdev.netmask[1],lwipdev.netmask[2],lwipdev.netmask[3]);

//解析出通过DHCP获取到的默认网关

lwipdev.gateway[3]=(uint8_t)(gw>>24);

lwipdev.gateway[2]=(uint8_t)(gw>>16);

lwipdev.gateway[1]=(uint8_t)(gw>>8);

lwipdev.gateway[0]=(uint8_t)(gw);

printf("网

关.........%d.%d.%d.%drn",lwipdev.gateway[0],lwipdev.gateway[1],lwipdev.gateway[2],lwipdev.gateway[3]);

}

}

五、LWIP函数使用(RAW编程接口)

5.1  LWIP初始化配置

u32 ARPTimer=0; //ARP查询计时器

u32 DHCPfineTimer=0;   //DHCP精细处理计时器

u32 DHCPcoarseTimer=0;  //DHCP粗糙处理计时器

u32 DHCP_State=1;          //保存DHCP状态 1表示没有分配成功 0表示分配成功

 

/*

函数功能:  LWIP轮询任务

*/

void lwip_periodic_handle()

{

//每250ms调用一次tcp_tmr()函数

if(TCPTimer >= TCP_TMR_INTERVAL)

{

TCPTimer=0;

tcp_tmr();  //处理TCP协议请求

}

 

//ARP每5s周期性调用一次

if(ARPTimer >= ARP_TMR_INTERVAL)

{

ARPTimer=0;

etharp_tmr();

}

//每500ms调用一次dhcp_fine_tmr()

if(DHCPfineTimer >= DHCP_FINE_TIMER_MSECS)

{

DHCPfineTimer=0;

dhcp_fine_tmr(); //动态IP地址分配的事物处理

if(DHCP_State)lwip_dhcp_process_handle();  //DHCP处理

}

 

//每60s执行一次DHCP粗糙处理

if(DHCPcoarseTimer >= DHCP_COARSE_TIMER_MSECS)

{

DHCPcoarseTimer=0;

dhcp_coarse_tmr();

}  

}

 

//lwip控制结构体

typedef struct  

{

u8 remoteip[4]; //服务器主机IP地址 

u8 ip[4];        //本机IP地址

u8 netmask[4];  //子网掩码

u8 gateway[4];  //默认网关的IP地址

}__lwip_dev;

 

extern __lwip_dev lwipdev; //lwip信息结构体

 

__lwip_dev lwipdev; //lwip信息结构体

 

 

/*

函数功能: DHCP处理任务

*/

void lwip_dhcp_process_handle(void)

{

u32 ip=0,netmask=0,gw=0;

ip=lwip_netif.ip_addr.addr; //读取新IP地址

netmask=lwip_netif.netmask.addr;   //读取子网掩码

gw=lwip_netif.gw.addr;           //读取默认网关

 

if(ip!=0) //正确获取到IP地址的时候

{

DHCP_State=0; //表示分配成功

  //解析出通过DHCP获取到的IP地址

lwipdev.ip[3]=(uint8_t)(ip>>24); 

lwipdev.ip[2]=(uint8_t)(ip>>16);

lwipdev.ip[1]=(uint8_t)(ip>>8);

lwipdev.ip[0]=(uint8_t)(ip);

printf("动态分配

IP:..............%d.%d.%d.%drn",lwipdev.ip[0],lwipdev.ip[1],lwipdev.ip[2],lwipdev.ip[3]);

//解析通过DHCP获取到的子网掩码地址

lwipdev.netmask[3]=(uint8_t)(netmask>>24);

lwipdev.netmask[2]=(uint8_t)(netmask>>16);

lwipdev.netmask[1]=(uint8_t)(netmask>>8);

lwipdev.netmask[0]=(uint8_t)(netmask);

printf("子网掩

码............%d.%d.%d.%drn",lwipdev.netmask[0],lwipdev.netmask[1],lwipdev.netmask[2],lwipdev.netmask[3]);

//解析出通过DHCP获取到的默认网关

lwipdev.gateway[3]=(uint8_t)(gw>>24);

lwipdev.gateway[2]=(uint8_t)(gw>>16);

lwipdev.gateway[1]=(uint8_t)(gw>>8);

lwipdev.gateway[0]=(uint8_t)(gw);

printf("网

关.........%d.%d.%d.%drn",lwipdev.gateway[0],lwipdev.gateway[1],lwipdev.gateway[2],lwipdev.gateway[3]);

}

}

 4.7 配置一个定时器提供时间基准

4.8 初始化lwip动态获取IP地址

4.9 LWIP内存配置选择

LWIP可以选择使用系统库自带的函数malloc/free进行管理空间,也可以使用lwip自己的内存管理函数进行管理,源码默认就是使用lwip自己的内存管理方法,就是在初始化内存的时候定义一个数组,数组的大小在lwipopts.h文件MEM_SIZE宏定义的。

 

五、LWIP函数使用(RAW编程接口)

5.1  LWIP初始化配置

ip_addr_t ipaddr;   //IP地址

ip_addr_t netmask;  //子网掩码

ip_addr_t gw;       //网关

 

//全部初始化为0  -因为使用了动态IP地址分配

ipaddr.addr=0;

netmask.addr=0;

gw.addr=0;

 

/*1. 初始化LWIP内核*/

lwip_init();

/*2. 向网卡列表中添加一个网络设备*/

netif_add(&lwip_netif,&ipaddr,&netmask,&gw,NULL,ðernetif_init,ðernet_input);

/*3. 开启DHCP服务 */

dhcp_start(&lwip_netif);

/*4. 设置netif为默认网口*/

netif_set_default(&lwip_netif);

/*5. 打开netif网口*/

netif_set_up(&lwip_netif);

 

5.2 LWIP轮询函数处理

LWIP轮询期间:

 

1. 推荐每250ms周期性调用一次tcp_tmr()函数,处理TCP协议请求。

 

    超时时间LWIP使用TCP_TMR_INTERVAL宏进行了定义。

 

2. 推荐每5s周期性调用一次etharp_tmr()函数,清除ARP表中过期的数据。

 

    超时时间LWIP使用ARP_TMR_INTERVAL宏进行了定义。

 

3. (如果开启了动态IP分配功能)推荐每500ms周期性调用一次dhcp_fine_tmr()函数,处理DHCP动态IP地址分配请求。  如果IP地址获取成功,将会放在初始化时注册的网络设备结构体里(struct netif)。

 

    超时时间LWIP使用DHCP_FINE_TIMER_MSECS宏进行了定义。

 

4. (如果开启了动态IP分配功能)推荐每60s调用一次dhcp_coarse_tmr()函数,用于检查DHCP租约时间,并进行重新绑定。

 

     超时时间LWIP使用DHCP_COARSE_TIMER_MSECS宏进行了定义。

 

5. 在LWIP运行期间,当网卡收到数据时,还需要调用ethernetif_input函数读取网卡数据。

 

在函数ethernetif_input()主要完成两个工作

 

1、调用low_level_input(); 读取网卡实际数据。

 

2、调用netif->input();

 

所以,为了能够实时的读取数据,需要最快的速度轮询调用ethernetif_input函数。

 

5.3  LWIP编程RAW接口函数

tcp_new() 创建一个 TCP 的 PCB 控制块

tcp_bind() 为 TCP 的 PCB 控制块绑定一个本地 IP 地址和端口号

tcp_listen() 开始 TCP 的 PCB 监听

tcp_accept() 控制块 accept字段注册的回调函数,侦听到连接时被调用

tcp_accepted() 通知 LWIP 协议栈一个 TCP 连接被接受了

tcp_conect() 连接远端主机

tcp_write() 构造一个报文并放到控制块的发送缓冲队列中

tcp_sent() 控制块 sent 字段注册的回调函数,数据发送成功后被回调

tcp_output() 将发送缓冲队列中的数据发送出去

tcp_recv()控制块 recv 字段注册的回调函数,当接收到新数据时被调用

tcp_recved()当程序处理完数据后一定要调用这个函数,通知内核更新接收窗口

tcp_poll() 控制块 poll 字段注册的回调函数,该函数周期性调用

tcp_close() 关闭一个 TCP 连接

tcp_err() 控制块 err 字段注册的回调函数,遇到错误时被调用

tcp_abort() 中断 TCP 连接

 

5.4 创建TCP服务器示例

下面演示了TCP服务器创建步骤,测试服务器是否正常。

 

u8 TCP_Create(u16_t port)

{

struct tcp_pcb *pcb=NULL;

pcb=tcp_new(); //创建套接字

if(pcb==NULL)return 1;

if(tcp_bind(pcb,IP_ADDR_ANY,port)!=ERR_OK)return 2; //绑定端口号

pcb=tcp_listen(pcb); //开始监听

tcp_accept(pcb,TCP_accept);//等待连接

return 0;

}

 

err_t TCP_accept(void *arg, struct tcp_pcb *newpcb, err_t err)

{

u8 addr[4];

//tcp_setprio(newpcb, TCP_PRIO_MIN);  设置优先级

printf("有新的客户端连接!n");

addr[3]=(newpcb->remote_ip.addr>>24)&0xFF;

addr[2]=(newpcb->remote_ip.addr>>16)&0xFF;

addr[1]=(newpcb->remote_ip.addr>>8)&0xFF;

addr[0]=(newpcb->remote_ip.addr>>0)&0xFF;

printf("ip地址:%d.%d.%d.%dn",addr[0],addr[1],addr[2],addr[3]);

printf("端口号:%dn",newpcb->remote_port);

printf("当前队列剩余字节:%dn",tcp_sndbuf(newpcb));

tcp_write(newpcb,"1234567890",10,1); //将要发送的数据提交到发送队列(不会立即发送)

tcp_output(newpcb);   //提示系统现在,发送数据

tcp_sent(newpcb,TCP_sent);   //发送成功的回调函数

tcp_recv(newpcb,TCP_recv);

return ERR_OK;

}

 

err_t TCP_sent(void *arg, struct tcp_pcb *tpcb,u16_t len)

{

printf("成功发送:%d字节n",len);

//tcp_close(tpcb); //关闭客户端连接

return ERR_OK;

}

 

u8 rx_buff[1024];

err_t TCP_recv(void *arg, struct tcp_pcb *tpcb,struct pbuf *p, err_t err)

{

u32 rx_cnt=0;

struct pbuf *q;

memset(rx_buff,0,sizeof(rx_buff));

if(p==NULL)

{

  printf("客户端已经断开连接!n");

}

else

{

  for(q=p;q!=NULL;q=q->next)

  {

memcpy(rx_buff+rx_cnt,q->payload,q->len);

rx_cnt+=q->len;

  }

       pbuf_free(p); //释放PUFF

printf("成功接收:%d字节n",rx_cnt);

printf("收到的数据=%sn",rx_buff);

}

return ERR_OK;

}

 

5.5 创建TCP客户端示例

u8 TCP_Create(u16_t port)

{

struct tcp_pcb *pcb=NULL;

pcb=tcp_new(); //创建套接字

ip_addr_t ipaddr;

if(pcb==NULL)return 1;

IP4_ADDR(&ipaddr,192,168,31,54); //在ip_addr.h里定义

tcp_connect(pcb,&ipaddr,port,TCP_connected);

return 0;

}

 

 

err_t TCP_connected(void *arg, struct tcp_pcb *tpcb, err_t err)

{

u8 addr[4];

//tcp_setprio(newpcb, TCP_PRIO_MIN);  设置优先级

printf("服务器连接成功!n");

addr[3]=(tpcb->remote_ip.addr>>24)&0xFF;

addr[2]=(tpcb->remote_ip.addr>>16)&0xFF;

addr[1]=(tpcb->remote_ip.addr>>8)&0xFF;

addr[0]=(tpcb->remote_ip.addr>>0)&0xFF;

printf("服务器ip地址:%d.%d.%d.%dn",addr[0],addr[1],addr[2],addr[3]);

printf("服务器端口号:%dn",tpcb->remote_port);

printf("当前队列剩余字节:%dn",tcp_sndbuf(tpcb));

tcp_write(tpcb,"1234567890",10,1); //将要发送的数据提交到发送队列(不会立即发送)

tcp_output(tpcb); //提示系统现在,发送数据

tcp_sent(tpcb,TCP_sent); //发送成功的回调函数

tcp_recv(tpcb,TCP_recv);

return ERR_OK;

}

 

 

err_t TCP_sent(void *arg, struct tcp_pcb *tpcb,u16_t len)

{

printf("成功发送:%d字节n",len);

//tcp_close(tpcb); //关闭客户端连接

return ERR_OK;

}

 

 

u8 rx_buff[1024];

err_t TCP_recv(void *arg, struct tcp_pcb *tpcb,struct pbuf *p, err_t err)

{

u32 rx_cnt=0;

struct pbuf *q;

memset(rx_buff,0,sizeof(rx_buff));

if(p==NULL)

{

printf("服务器已经断开连接!n");

}

else

{

for(q=p;q!=NULL;q=q->next)

{

  memcpy(rx_buff+rx_cnt,q->payload,q->len);

  rx_cnt+=q->len;

}

printf("成功接收:%d字节n",rx_cnt);

printf("收到的数据=%sn",rx_buff);

}

return ERR_OK;

}

posted @ 2023-02-15 16:02  分类DHCP  阅读(1057)  评论(0)    收藏  举报