热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

【方法】lwip2.0.2配置DHCP自动从路由器获取IP地址和DNS服务器地址,并设置NetBIOS计算机名

本文使用是STM32F107VC单片机的有线以太网外设ETH和DP83848外部PHY收发器。如果使用的是KeiluVision5的编译器,需要检查一下lwipin

本文使用是STM32F107VC单片机的有线以太网外设ETH和DP83848外部PHY收发器。

如果使用的是Keil uVision5的编译器,需要检查一下lwip/include/arch/cc.h里面是否有下面这一行:

#define PACK_STRUCT_BEGIN __packed // struct前的__packed

否则NetBIOS服务是无法正常工作的。

【项目中需要添加的lwip文件】

httpd服务器模块:复制lwip/apps/httpd文件夹下的fs.c、fsdata.c、fsdata.h、httpd.c和httpd_structs.h,但只把fs.c和httpd.c添加到Keil项目里。

netbiosns模块:复制lwip/apps/netbiosns文件夹,并把其中的c文件添加到Keil项目里。

【lwipopts.h】

#define NO_SYS 1 // 无操作系统#define LWIP_NETCONN 0
#define LWIP_SOCKET 0
#define LWIP_STATS 0#define MEM_ALIGNMENT 4 // STM32单片机是32位的单片机, 因此是4字节对齐的#define SYS_LIGHTWEIGHT_PROT 0 // 不进行临界区保护// ★配置DHCP
#define LWIP_DHCP 1
#define LWIP_NETIF_HOSTNAME 1// ★配置DNS
#define LWIP_DNS 1
#define LWIP_RAND() ((u32_t)rand())

【main.c(部分代码)】

#include
#include
#include "lwip/apps/httpd.h" // http服务器
#include "lwip/apps/netbiosns.h" // NetBIOS服务
#include "lwip/dhcp.h" // ★DHCP客户端
#include "lwip/dns.h" // ★DNS客户端
#include "lwip/init.h"
#include "lwip/timeouts.h"
#include "netif/ethernet.h"
#include "ETH.h" // 自己编写的网卡驱动头文件err_t ethernetif_init(struct netif *netif);
void ethernetif_input(struct netif *netif);
void dns_test(void); // DNS测试函数/* 省略了一些无关函数的代码 *//* RTC时间转化为毫秒数 (lwip协议栈要求实现的函数) */
// 该函数必须保证: 除非定时器溢出, 否则后获取的时间必须大于先获取的时间
uint32_t sys_now(void)
{uint32_t sec[2];uint32_t div, milli;do{time(&sec[0]); // 秒div = rtc_divider();time(&sec[1]);} while (sec[0] != sec[1]);// CNT是在DIV从P-1跳变到P-2瞬间发生更新的 (P=RTC_PRESCALER)if (div == RTC_PRESCALER - 1)milli = div;elsemilli = RTC_PRESCALER - div - 2;milli = milli * 1000 / RTC_PRESCALER; // 毫秒return sec[0] * 1000 + milli;
}int main(void)
{struct dhcp *dhcp;struct netif dp83848;uint8_t ip_displayed = 0;/* 网卡初始化过程省略 */lwip_init();netif_add(&dp83848, IP_ADDR_ANY, IP_ADDR_ANY, IP_ADDR_ANY, NULL, ethernetif_init, ethernet_input); // ★IP地址, 子网掩码和默认网关全部为IP_ADDR_ANYnetif_set_default(&dp83848);netif_set_up(&dp83848);dp83848.hostname = "STM32F107VC_ETH"; // ★路由器中显示的名称dhcp_start(&dp83848);// 需要添加lwip/apps/netbiosns/netbiosns.cnetbiosns_init();netbiosns_set_name("STM32F107VC"); // ★计算机名 (测试方法: (1)ping 计算机名 (2)用浏览器访问http://计算机名/)// 注意: 路由器中显示的名称可以和计算机名不同httpd_init(); // 初始化lwip自带的http服务器 (lwip/apps/httpd/*)while (1){// 有数据包就接收数据包if (recven && ETH_GetDMAFlagStatus(ETH_DMA_FLAG_R) == SET){ETH_DMAClearFlag(ETH_DMA_FLAG_R);while (ETH_GetDMARxDescFlagStatus(DMARxDescToGet, ETH_DMARxDesc_OWN) == RESET)ethernetif_input(&dp83848);ETH_DMAITConfig(ETH_DMA_IT_RBU, ENABLE); // 若RBU中断已关闭, 则再次开启}// ★显示DHCP分配到的IP地址if (dhcp_supplied_address(&dp83848)){if (!ip_displayed){dhcp = netif_dhcp_data(&dp83848);printf("IP address: %s\n", ip4addr_ntoa(&dhcp->offered_ip_addr));printf("Subnet mask: %s\n", ip4addr_ntoa(&dhcp->offered_sn_mask));printf("Default gateway: %s\n", ip4addr_ntoa(&dhcp->offered_gw_addr));
#if LWIP_DNSprintf("DNS Server: %s\n", ip4addr_ntoa(dns_getserver(0)));
#endifip_displayed = 1;dns_test(); // 测试DNS解析}}elseip_displayed = 0;// lwip定时处理sys_check_timeouts();}
}void HardFault_Handler(void)
{printf("Hard Error!\n");while (1);
}

【dns_test.c】

#include "lwip/tcp.h"
#include "lwip/dns.h"static err_t test_connected(void *arg, struct tcp_pcb *tpcb, err_t err)
{printf("Connected! err=%d\n", err);err = tcp_close(tpcb);if (err == ERR_OK)printf("Connection is successfully closed!\n");elseprintf("Connection cannot be closed now! err=%d\n", err);return ERR_OK;
}static void test_err(void *arg, err_t err)
{printf("Connection error! code=%d\n", err);
}static void connect_test(const ip_addr_t *ipaddr)
{struct tcp_pcb *tpcb;printf("Connecting to %s...\n", ip4addr_ntoa(ipaddr));tpcb = tcp_new();tcp_connect(tpcb, ipaddr, 80, test_connected);tcp_err(tpcb, test_err);
}static void dns_found(const char *name, const ip_addr_t *ipaddr, void *callback_arg)
{if (ipaddr != NULL){printf("DNS Found IP: %s\n", ip4addr_ntoa(ipaddr));connect_test(ipaddr);}elseprintf("DNS Not Found IP!\n");
}void dns_test(void)
{ip_addr_t dnsip;err_t err = dns_gethostbyname("zh.arslanbar.net", &dnsip, dns_found, NULL);if (err == ERR_OK){printf("In cache! IP: %s\n", ip4addr_ntoa(&dnsip));connect_test(&dnsip);}elseprintf("Not in cache! err=%d\n", err); // 缓存中没有时需要等待DNS解析完毕在dns_found回调函数中返回结果
}

【程序运行结果】

分配到的IP地址:

路由器中显示的设备名:(因为笔者没有把开发板接到路由器上而是电脑的有线网卡上,所以用DHCP Server for Windows这个软件在Win7电脑上模拟了一个DHCP服务器)

ping命令ping通计算机名(NetBIOS):

用计算机名访问开发板上的http服务器:

由于无线路由器比较远,所以笔者是把开发板用网线直接连接到电脑的有线网卡上的,电脑的无线网卡连接无线路由器。

Windows Server版有DHCP服务器功能,但普通用户版(如win7,xp等系统)没有这样的功能,需要安装第三方DHCP服务器软件。下面介绍一下DHCP Server for Windows这款软件,下载地址是DHCP Server for Windows

下载后解压到一个文件夹里面。

首先需要在Windows的无线网卡里面开启网络共享,使有线网卡(本地连接)能够通过无线网卡访问Internet。在笔者的电脑上,有线网卡的网线是插在开发板上的,而无线网卡是连接到无线路由器上的。下面介绍的方法可以使开发板也可以正常上网。

(笔者最近发现,只要在Windows系统上开了ICS网络共享,即使不安装dhcpsrv这个软件,开发板也能分配到IP地址,但是不能自定义DNS服务器的地址,而且每次获取的IP地址都不相同,影响开发)

勾选后点击确定,有线网卡的IP地址会被系统自动改为192.168.137.1这个地址。

运行dhcpwiz.exe配置DHCP服务器,选择插了开发板网线的网卡:

HTTP, TFTP, DNS都不用勾选。这里的DNS地址估计是当默认DNS服务器填写的是默认网关的IP地址时,自动转发到的DNS服务器真实地址。

配置好有线网卡的IP地址,以及DHCP服务器的IP地址分配范围:

在Advanced选项里面设置好默认网关(也就是电脑有线网卡的IP地址)和DNS服务器的地址(8.8.8.8):

写入ini文件,并点击next,启动DHCP服务器(可以设置为windows系统服务)

最后,建议在电脑有线网卡与STM32开发板之间加接一个交换机。否则STM32开发板每次烧写或复位,电脑上的有线网卡都要重新初始化一次,导致dhcpsrv服务不停的重启,长时间分配不到IP地址,降低开发效率。不过,连接或断开无线网也会导致dhcpsrv服务重启。

如果想要让开发板能连接VMware虚拟机里面的网络环境为NAT的电脑,只需要在主机里的VMware Network Adapter VMnet8网卡(IP地址和虚拟机里面的网关相同的网卡)上添加ICS到本地连接(有线网卡)就行,此时需要关闭无线网卡上的ICS。


推荐阅读
  • 本文介绍了C++中省略号类型和参数个数不确定函数参数的使用方法,并提供了一个范例。通过宏定义的方式,可以方便地处理不定参数的情况。文章中给出了具体的代码实现,并对代码进行了解释和说明。这对于需要处理不定参数的情况的程序员来说,是一个很有用的参考资料。 ... [详细]
  • 本文介绍了在Linux下安装Perl的步骤,并提供了一个简单的Perl程序示例。同时,还展示了运行该程序的结果。 ... [详细]
  • 本文介绍了Web学习历程记录中关于Tomcat的基本概念和配置。首先解释了Web静态Web资源和动态Web资源的概念,以及C/S架构和B/S架构的区别。然后介绍了常见的Web服务器,包括Weblogic、WebSphere和Tomcat。接着详细讲解了Tomcat的虚拟主机、web应用和虚拟路径映射的概念和配置过程。最后简要介绍了http协议的作用。本文内容详实,适合初学者了解Tomcat的基础知识。 ... [详细]
  • 在重复造轮子的情况下用ProxyServlet反向代理来减少工作量
    像不少公司内部不同团队都会自己研发自己工具产品,当各个产品逐渐成熟,到达了一定的发展瓶颈,同时每个产品都有着自己的入口,用户 ... [详细]
  • imx6ull开发板驱动MT7601U无线网卡的方法和步骤详解
    本文详细介绍了在imx6ull开发板上驱动MT7601U无线网卡的方法和步骤。首先介绍了开发环境和硬件平台,然后说明了MT7601U驱动已经集成在linux内核的linux-4.x.x/drivers/net/wireless/mediatek/mt7601u文件中。接着介绍了移植mt7601u驱动的过程,包括编译内核和配置设备驱动。最后,列举了关键词和相关信息供读者参考。 ... [详细]
  • 在CentOS/RHEL 7/6,Fedora 27/26/25上安装JAVA 9的步骤和方法
    本文介绍了在CentOS/RHEL 7/6,Fedora 27/26/25上安装JAVA 9的详细步骤和方法。首先需要下载最新的Java SE Development Kit 9发行版,然后按照给出的Shell命令行方式进行安装。详细的步骤和方法请参考正文内容。 ... [详细]
  • 使用nodejs爬取b站番剧数据,计算最佳追番推荐
    本文介绍了如何使用nodejs爬取b站番剧数据,并通过计算得出最佳追番推荐。通过调用相关接口获取番剧数据和评分数据,以及使用相应的算法进行计算。该方法可以帮助用户找到适合自己的番剧进行观看。 ... [详细]
  • 本文详细介绍了GetModuleFileName函数的用法,该函数可以用于获取当前模块所在的路径,方便进行文件操作和读取配置信息。文章通过示例代码和详细的解释,帮助读者理解和使用该函数。同时,还提供了相关的API函数声明和说明。 ... [详细]
  • Spring源码解密之默认标签的解析方式分析
    本文分析了Spring源码解密中默认标签的解析方式。通过对命名空间的判断,区分默认命名空间和自定义命名空间,并采用不同的解析方式。其中,bean标签的解析最为复杂和重要。 ... [详细]
  • 向QTextEdit拖放文件的方法及实现步骤
    本文介绍了在使用QTextEdit时如何实现拖放文件的功能,包括相关的方法和实现步骤。通过重写dragEnterEvent和dropEvent函数,并结合QMimeData和QUrl等类,可以轻松实现向QTextEdit拖放文件的功能。详细的代码实现和说明可以参考本文提供的示例代码。 ... [详细]
  • 本文介绍了在Windows环境下如何配置php+apache环境,包括下载php7和apache2.4、安装vc2015运行时环境、启动php7和apache2.4等步骤。希望对需要搭建php7环境的读者有一定的参考价值。摘要长度为169字。 ... [详细]
  • Android源码深入理解JNI技术的概述和应用
    本文介绍了Android源码中的JNI技术,包括概述和应用。JNI是Java Native Interface的缩写,是一种技术,可以实现Java程序调用Native语言写的函数,以及Native程序调用Java层的函数。在Android平台上,JNI充当了连接Java世界和Native世界的桥梁。本文通过分析Android源码中的相关文件和位置,深入探讨了JNI技术在Android开发中的重要性和应用场景。 ... [详细]
  • C++字符字符串处理及字符集编码方案
    本文介绍了C++中字符字符串处理的问题,并详细解释了字符集编码方案,包括UNICODE、Windows apps采用的UTF-16编码、ASCII、SBCS和DBCS编码方案。同时说明了ANSI C标准和Windows中的字符/字符串数据类型实现。文章还提到了在编译时需要定义UNICODE宏以支持unicode编码,否则将使用windows code page编译。最后,给出了相关的头文件和数据类型定义。 ... [详细]
  • 3.223.28周学习总结中的贪心作业收获及困惑
    本文是对3.223.28周学习总结中的贪心作业进行总结,作者在解题过程中参考了他人的代码,但前提是要先理解题目并有解题思路。作者分享了自己在贪心作业中的收获,同时提到了一道让他困惑的题目,即input details部分引发的疑惑。 ... [详细]
  • Java在运行已编译完成的类时,是通过java虚拟机来装载和执行的,java虚拟机通过操作系统命令JAVA_HOMEbinjava–option来启 ... [详细]
author-avatar
UWBCZ
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有