前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >RT-Thread实战笔记|DHCP原理介绍及使用

RT-Thread实战笔记|DHCP原理介绍及使用

作者头像
用户8913398
发布2021-09-10 16:33:20
9240
发布2021-09-10 16:33:20
举报
文章被收录于专栏:嵌入式实验基地

什么是DHCP

动态主机配置协议DHCP(Dynamic Host Configuration Protocol)是一种对基于TCP/IP协议主机的网络参数进行动态配置和集中管理的协议,可以实现:

  • 为网络主机分配IP地址。

DHCP可以提供两种地址分配机制,网络管理员可以根据网络需求为不同的主机选择不同的分配策略。

动态分配机制:

通过DHCP为主机分配一个有使用期限(这个使用期限通常叫做租期)的IP地址。这种分配机制适用于主机需要临时接入网络或者空闲地址数小于网络主机总数且主机不需要永久连接网络的场景。例如,企业出差员工的便携机、咖啡厅的移动终端为了临时接入网络需要获取IP地址。

静态分配机制:

网络管理员通过DHCP为指定的主机分配固定的IP地址。这种分配机制适用于对IP地址有特殊要求的主机,例如企业的文件服务器由于需要对外网用户提供服务,需要使用固定的IP地址。相比手工静态配置IP地址,通过DHCP方式静态分配机制避免人工配置发生错误,方便管理员统一维护管理。

  • 为网络主机提供除IP地址以外的网络参数。

例如DNS服务器的IP地址、路由信息、网关地址等。

DHCP也是一种基于客户端/服务器模型的协议。DHCP服务器上不需要手工记录网络中所有主机MAC地址和IP地址的对应关系,而是通过地址池管理可供某网段主机使用的IP地址。

当主机成功向DHCP服务器申请到IP地址后,DHCP服务器才会记录主机MAC地址和IP地址的对应关系,且此过程不需要人工参与。同时,DHCP服务器还可以为某个网段内主机动态分配相同的网络参数,例如,缺省网关、DNS服务器的IP地址等。

DHCP可以把同一个地址在不同时间分配给不同的主机,当主机不需要使用地址时,可以释放此地址,供其他主机使用,从而实现了IP地址的重复利用。

  • DHCP的优点

1、降低网络接入成本:

2、降低主机配置成本:

3、提高IP地址利用率:

4、方便统一管理:

DHCP报文格式及实现原理

报文格式

括号里的数字表示字段的长度,单位是字节

报文名称

说明

DHCP DISCOVER

DHCP客户端首次登录网络时进行DHCP交互过程发送的第一个报文,用来寻找DHCP服务器。

DHCP OFFER

DHCP服务器用来响应DHCP DISCOVER报文,此报文携带了各种配置信息。

DHCP REQUEST

此报文用于以下三种用途。1、客户端初始化后,发送广播的DHCP REQUEST报文来回应服务器的DHCP OFFER报文。2、客户端重启后,发送广播的DHCP REQUEST报文来确认先前被分配的IP地址等配置信息。3、当客户端已经和某个IP地址绑定后,发送DHCP REQUEST单播或广播报文来更新IP地址的租约。

DHCP ACK

服务器对客户端的DHCP REQUEST报文的确认响应报文,客户端收到此报文后,才真正获得了IP地址和相关的配置信息。

DHCP NAK

服务器对客户端的DHCP REQUEST报文的拒绝响应报文,例如DHCP服务器收到DHCP REQUEST报文后,没有找到相应的租约记录,则发送DHCP NAK报文作为应答,告知DHCP客户端无法分配合适IP地址。

DHCP DECLINE

当客户端发现服务器分配给它的IP地址发生冲突时会通过发送此报文来通知服务器,并且会重新向服务器申请地址。

DHCP RELEASE

客户端可通过发送此报文主动释放服务器分配给它的IP地址,当服务器收到此报文后,可将这个IP地址分配给其它的客户端。

DHCP INFORM

DHCP客户端获取IP地址后,如果需要向DHCP服务器获取更为详细的配置信息(网关地址、DNS服务器地址),则向DHCP服务器发送DHCP INFORM请求报文。

  • DHCP报文中的Options字段

DHCP报文中的Options字段可以用来存放普通协议中没有定义的控制信息和参数。如果用户在DHCP服务器端配置了Options字段,DHCP客户端在申请IP地址的时候,会通过服务器端回应的DHCP报文获得Options字段中的配置信息。

Options字段的格式如下图1所示。

Options字段的格式

Options字段由Type、Length和Value三部分组成。这三部分的表示含义如下所示:

字段

长度

含义

Type

1字节

该字段表示信息类型。

Length

1字节

该字段表示后面信息内容的长度。

Value

其长度为Length字段所指定

该字段表示信息内容。

DHCP Options选项的取值范围为1~255,如下表2所示,介绍DHCP Options的部分知名选项

实现原理

配图摘自网络

配图摘自网络

  • 发现阶段

DHCP客户端在网络中广播发送DHCP DISCOVER请求报文,发现DHCP服务器,请求IP地址租约

  • 提供阶段

DHCP服务器通过DHCP OFFER报文向DHCP客户端提供IP地址预分配

  • 选择阶段

DHCP客户端通过DHCP REQUEST报文确认选择第一个DHCP服务器为它提供IP地址自动分配服务

  • 确认阶段

被选择的DHCP服务器通过DHCP ACK报文把在DHCP OFFER报文中准备的IP地址租约给对应DHCP客户端

关于DHCP的内容还是比较多的,仅仅做了一些简单介绍

rt-thread中使用DHCP功能

本次基于env环境搭建工程,基于STM32F407开发板,LAN8720网口

现在gitbub down下来rt-thread的bsp包,

进去到探索者的BSP包,右击选择comEmu Here

在弹出的env操作框中输入menuconfig,添加网络组件

rt-thread Configuration-->rt-Thread Components-->Network 进入到网络组件

Socket abstraction layer 默认选项即可

Network interface device 除了IPV6,都选上

light weight tcp/ip stack 这个里面内容比较多,根据自己的需要选择相应的功能即可,本次我们测试DHCP功能,选择DHCP功能

退出保存即可

接下来我们使用keil5编译工程,在env环境输入scons --target=keil5,生成keil5环境的工程,如果你用IAR,换成IAR即可,编译完成,此时我们就可以到熟悉的keil5环境中操作了

关于DHCP的代码已经添加进来了,编译下载,看看效果

需要注意的是,需要经过路由器连接,电脑连接路由器,开发板网口也连接路由器,输入ifconfig,发现已经自动获取到IP地址啦

接下来经典ping一下我们的主机

礼尚往来,主机ping一下我们的开发板

挺好...

接下来,我们把开发板作为客户端,与主机(网络调试助手)进行通讯

添加一下函数

代码语言:javascript
复制
/**===================tcpclient=====================*/
#define BUFSZ 512

static void tcpclient(int argc, char **argv)
{
 int ret;
 char *recv_data;
 struct hostent *host;
 int sock, bytes_received;
 struct sockaddr_in server_addr;
 const char *url;
 int port;

 if (argc < 3)
 {
  rt_kprintf("Usage:tcpclient URL PORT\n");
  rt_kprintf("Like: tcpcilent 192.168.1.20 5000");
  return;
 }
 url = argv[1];
 port = strtoul(argv[2], 0, 10);

 host = lwip_gethostbyname(url);

 recv_data = rt_malloc(BUFSZ);
 if (recv_data == RT_NULL)
 {
  rt_kprintf("No memory\n");
  return;
 }
 /* 创建一个 socket,类型是 SOCKET_STREAM,TCP 类型 */
 if ((sock = lwip_socket(AF_INET, SOCK_STREAM, 0)) == -1)
 {
  /* 创建 socket 失败 */
  rt_kprintf("Socket error\n");

  /* 释放接收缓冲 */
  rt_free(recv_data);
  return;
 }

 server_addr.sin_family = AF_INET;
 server_addr.sin_port = htons(port);
 server_addr.sin_addr = *((struct in_addr *)host->h_addr);
 rt_memset(&(server_addr.sin_zero), 0, sizeof(server_addr.sin_zero));

 if (lwip_connect(sock, (struct sockaddr *)&server_addr, sizeof(struct sockaddr)) == -1)
 {
  rt_kprintf("Connect fail\n");
  lwip_close(sock);
  rt_free(recv_data);
  return;
 }

 while (1)
 {
  bytes_received = lwip_recv(sock, recv_data, BUFSZ - 1, 0);
  if (bytes_received < 0)
  {
   lwip_close(sock);
   rt_kprintf("\n received error, close the socket.\r\n");
   break;
  }
  else if (bytes_received == 0)
  {
   rt_kprintf("\n received warning, recv function return 0.\r\n");
   continue;
  }
  recv_data[bytes_received] = '\0';

  if (strncmp(recv_data, "q", 1) == 0 || strncmp(recv_data, "Q", 1) == 0)
  {
   lwip_close(sock);
   rt_kprintf("\n got a 'q' or 'Q', close the socket. \r\n");
   rt_free(recv_data);
   break;
  }
  else
  {
   rt_kprintf("\n Receive data = %s", recv_data);
  }

  ret = lwip_send(sock, recv_data, strlen(recv_data), 0);
  if (ret < 0)
  {
   lwip_close(sock);
   rt_kprintf("\n send error, close the socket.\r\n");
   rt_free(recv_data);
   break;
  }
  else if (ret == 0)
  {
   rt_kprintf("\n Send warning, send funcion returun 0. \r\n");
  }
 }
}
MSH_CMD_EXPORT(tcpclient, tcpclient sample);

网络调试助手作为服务器

PC端IPV4地址设置如下

网络调试助手

控制台输入tcpclient 192.168.1.106 8080,连接成功,然后发送数据至网络调试助手,测试成功。over

经验交流

欢迎关注小飞哥公众号,加好友一起交流,进群一起探讨,真开心遇到优秀的你!

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2021-08-26,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 小飞哥玩嵌入式 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • DHCP报文格式及实现原理
    • 报文格式
      • 实现原理
      • rt-thread中使用DHCP功能
      • 经验交流
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档