热度 16
2015-2-4 10:36
1434 次阅读|
0 个评论
已刊登在《无线电》2月刊 一 实例背景 最近一个做智能家居的朋友面临这样的一个烦恼,他想让用户通过智能手机在家里方便地控制家居设备,又想让用户免除下载安装 App 的麻烦,通过浏览器直接打开设备内嵌的网页便可实现控制。但是设备的 IP 地址都是通过家里的路由器自动获得的,设备上又没有屏幕来显示其 IP 地址。问我有没有办法不输入 IP 地址来实现浏览器访问该设备网页的办法,就是类似 DNS 之类,但是无需连外网,只在家庭网络内能访问即可。 这使我想起一个古老的协议, NetBIOS(Network Basic Input/Output System) 。这个在上世纪 80 年代由 IBM 开发的协议,主要用于数十台左右计算机组成的小型局域网,该协议的主要用途之一就是把计算机名称解析为相应 IP 地址。如果每个设备有一个固定名字,在实现了 NetBIOS 的前提下,用户在浏览器里输入该设备的名字,然后通过 NetBIOS 解析,便可实现访问该设备网页的这个功能了。而且 NetBIOS 占用系统资源少,在单片机上运行不成问题。于是推荐这个朋友在他的设备上实现了 NetBIOS 协议,解决了他的烦恼。 除了智能家居,在当下物联网时代,想必还有其他应用也会遇到类似问题,就拿手头的 WIZnet-W5500 评估板实现了一下 NetBIOS ,希望能对做网络设备开发的朋友有所帮助。在用 W5500 实现之前,我们还是先在 PC 上看一下 NetBIOS 到底是一个什么东西。 二 NetBIOS 协议 我们知道在 DOS 命令下可以通过 PING 主机名获得另外一台电脑的 IP 地址,实际上就是通过 NETBIOS 进行的。在 Windows 操作系统 中,默认情况下在安装 TCP/IP 协议 后会自动安装 NetBIOS 。查看方法如下: 本地连接 属性的中“高级 TCP/IP 设置”窗口中选择“ WINS ”选项卡,在“ NetBIOS 设置”区域中就可以设置相应的 NetBIOS ,如图 1 : 图 1 WINS 下的 NetBIOS 设置 Ping 主机名的第一个数据包就是 NBNS ( NetBIOS Name Server), 协议包,它是 TCP/IP 上的 NetBIOS (NetBT) 协议族的一部分,它在基于 NetBIOS 名称访问的网络上提供主机名和地址映射方法。 NBNS 是动态 DNS 的一种, Microsoft 的 NBNS 实现称为 WINS 。 NetBIOS 的报文类型较多、结构复杂,不同的网络环境及不同的用途中,会使用不同报文,可用端口进行区分, WINS 协议中, NetBIOS 名字报文、数据报报文及会话报文分别使用 TCP 137 、 138 和 139 端口。 NetBIOS 数据报有很多不同格式,主要取决于服务和信息类型,以及用以传送 NetBIOS 数据报的传输协议。 NetBIOS 协议架构可见图 2 ,其中包含三种基本服务: NAME 、 SESSION 和 DATAGRAM ,其中 NAME 所用协议就是 NBNS 协议。 图 2 : NetBIOS 协议架构 下面看一下 WINS 协议使用的报文 NETBIOS 的名字报文( NAME )的总体格式如表 1 : 表 1 NetBIOS 名字报文格式 事物 ID ( 2bytes ) 通用标志( 2bytes ) 问题记录个数( 2bytes ) 回答记录个数( 2bytes ) 权威记录个数( 2bytes ) 附加记录个数( 2bytes ) 问题记录(若干字节) 回答记录(若干字节) 权威记录(若干字节) 附加记录(若干字节) 报文的前 12 字节总称为 NETBIOS 名字报文的首部,通过首部我们可以判断出是否为名字查询的报文。 NETBIOS 名字报文中最常见的是携带问题记录的报文,问题记录的格式如表 2 : 表 2 NetBIOS 名字报文中问题记录格式 问题名称(若干字节) 问题类型( 2 bytes ) 问题类别( 2bytes ) 通过携带问题记录的报文,我们可以得到要查询的名字字符,如果和本机名相符,就发送报文响应,响应中带有 IP 地址,发送广播的主机就会得到该 IP 地址。 三 W5500EVB 实现 NETBIOS 名字报文解析 了解了 NETBIOS 协议之后,下面就让我们通过 W5500EVB 做一个嵌入 NetBIOS 的简单实验。 实验目的:通过在 DOS 下 ping 该设备名“ WIZNRTW5500 ”,可以得到开发板的 IP 地址。 硬件环境 单片机: STM32F103RC , 256K 字节 Flash , 48K 字节 SRAM , 2K 字节 EEPROM 以太网控制器: W5500 , SPI 接口与单片机相连 电源: USB 供电 硬件外设:板载 LED 开发工具 : Keil 测试软件:串口调试助手,网络调试助手 看代码之前,我们还是先来了解一下整个的程序流程,如图 3 所示整个程序采用查询方式 , 通过 DHCP 子程序成功获取 IP 后可执行 NBNS 服务。同时 W5500EVB 设置成 HTTP Server ,可以接收,并处理 TCP Client 发来的数据 图 3 :主程序流程图 本文主要讨论如何在单片机上实现 NETBIOS 名字解析服务, DHCP 和 TCP Server 相关部分子程序在此不再详细介绍,根据 NETBIOS 名字解析服务子程序流程图(如图 4 示),我们可以得知当查询到 137 端口收到网络的 UDP 数据包时,读取数据包并进行判断是否为 NETBIOS 名字报文,如果是就将解析出的名字与本机名比较,如果一致就回复报文。 图 4 : NBNS 程序流程图 在此贴出 NETBIOS 部分代码,要获取完整代码,请到 http://pan.baidu.com/s/1nt9MQKh 上进行下载。 void do_netbios(void) { unsigned char state; unsigned int len; 1 state = getSn_SR(NETBIOS_SOCK); switch(state) { case SOCK_UDP: 2 if((len=getSn_RX_RSR(NETBIOS_SOCK))0) { unsigned char rem_ip_addr ; uint16 rem_udp_port; 3 char netbios_name ; 4 NETBIOS_HDR* netbios_hdr; 5 NETBIOS_NAME_HDR* netbios_name_hdr; 6 len=recvfrom(NETBIOS_SOCK,(unsignedchar*)netbios_rx_buf,len,rem_ip_addr,rem_udp_port); printf(“rem_ip_addr=%d.%d.%d.%d:%d\r\n”,rem_ip_addr ,rem_ip_addr ,rem_ip_addr ,rem_ip_addr ,rem_udp_port); 7 netbios_hdr = (NETBIOS_HDR*)netbios_rx_buf; 8 netbios_name_hdr = (NETBIOS_NAME_HDR*)(netbios_hdr+1); /* if the packet is a NetBIOS name query question */ 9 if(((netbios_hdr-flags ntohs(NETB_HFLAG_OPCODE)) == ntohs(NETB_HFLAG_OPCODE_NAME_QUERY)) ((netbios_hdr-flags ntohs(NETB_HFLAG_RESPONSE)) == 0) (netbios_hdr-questions == ntohs(1))) { printf(“netbios name query question\r\n”); /* decode the NetBIOS name */ 10 netbios_name_decoding( (char*)(netbios_name_hdr-encname), netbios_name, sizeof(netbios_name)); printf(“name is %s\r\n”,netbios_name); /* if the packet is for us */ 11 if (strcmp(netbios_name, NETBIOS_W5500_NAME) == 0) { uint8 ip_addr ; NETBIOS_RESP *resp = (NETBIOS_RESP*)netbios_tx_buf; /* prepare NetBIOS header response */ 12 resp-resp_hdr.trans_id = netbios_hdr-trans_id; resp-resp_hdr.flags = htons(NETB_HFLAG_RESPONSE | NETB_HFLAG_OPCODE_NAME_QUERY | NETB_HFLAG_AUTHORATIVE | NETB_HFLAG_RECURS_DESIRED); 继续阅读:http://blog.csdn.net/wiznet2012/article/details/43451805