这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界 » 论坛首页 » 嵌入式开发 » STM32 » W5500教程之用W5500实现NetBIOS的案例分享

共2条 1/1 1 跳转至

W5500教程之用W5500实现NetBIOS的案例分享

高工
2020-10-29 22:00:09     打赏

基于W5500的NetBIOS应用实例

一实例背景

最近一个做智能家居的朋友面临这样的一个烦恼,他想让用户通过智能手机在家里方便地控制家居设备,又想让用户免除下载安装App的麻烦,通过浏览器直接打开设备内嵌的网页便可实现控制。但是设备的IP地址都是通过家里的路由器自动获得的,设备上又没有屏幕来显示其IP地址。问我有没有办法不输入IP地址来实现浏览器访问该设备网页的办法,就是类似DNS之类,但是无需连外网,只在家庭网络内能访问即可。

这使我想起一个古老的协议,NetBIOS(NetworkBasicInput/OutputSystem)。这个在上世纪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:

基于W5500的NetBIOS应用实例

Ping主机名的第一个数据包就是NBNS(NetBIOSNameServer),协议包,它是TCP/IP上的NetBIOS(NetBT)协议族的一部分,它在基于NetBIOS名称访问的网络上提供主机名和地址映射方法。NBNS是动态DNS的一种,Microsoft的NBNS实现称为WINS。NetBIOS的报文类型较多、结构复杂,不同的网络环境及不同的用途中,会使用不同报文,可用端口进行区分,WINS协议中,NetBIOS名字报文、数据报报文及会话报文分别使用TCP137、138和139端口。

NetBIOS数据报有很多不同格式,主要取决于服务和信息类型,以及用以传送NetBIOS数据报的传输协议。NetBIOS协议架构可见图2,其中包含三种基本服务:NAME、SESSION和DATAGRAM,其中NAME所用协议就是NBNS协议。

基于W5500的NetBIOS应用实例

图2:NetBIOS协议架构

下面看一下WINS协议使用的报文NETBIOS的名字报文(NAME)的总体格式如表1:

表1NetBIOS名字报文格式

事物ID(2bytes)通用标志(2bytes)问题记录个数(2bytes)回答记录个数(2bytes)权威记录个数(2bytes)附加记录个数(2bytes)问题记录(若干字节)回答记录(若干字节)权威记录(若干字节)附加记录(若干字节)

报文的前12字节总称为NETBIOS名字报文的首部,通过首部我们可以判断出是否为名字查询的报文。

NETBIOS名字报文中最常见的是携带问题记录的报文,问题记录的格式如表2:

表2NetBIOS名字报文中问题记录格式

问题名称(若干字节)

问题类型(2bytes)

问题类别(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设置成HTTPServer,可以接收,并处理TCPClient发来的数据

基于W5500的NetBIOS应用实例

图3:主程序流程图

本文主要讨论如何在单片机上实现NETBIOS名字解析服务,DHCP和TCPServer相关部分子程序在此不再详细介绍,根据NETBIOS名字解析服务子程序流程图(如图4示),我们可以得知当查询到137端口收到网络的UDP数据包时,读取数据包并进行判断是否为NETBIOS名字报文,如果是就将解析出的名字与本机名比较,如果一致就回复报文。

基于W5500的NetBIOS应用实例

图4:NBNS程序流程图

在此贴出NETBIOS部分代码,要获取完整代码,请到上进行下载。

voiddo_netbios(void)

{

unsignedcharstate;

unsignedintlen;

1state=getSn_SR(NETBIOS_SOCK);

switch(state)

{

caseSOCK_UDP:

2if((len=getSn_RX_RSR(NETBIOS_SOCK))>0)

{

unsignedcharrem_ip_addr[4];

uint16rem_udp_port;

3charnetbios_name[NETBIOS_NAME_LEN+1];

4NETBIOS_HDR*netbios_hdr;

5NETBIOS_NAME_HDR*netbios_name_hdr;

6len=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[0],rem_ip_addr[1],rem_ip_addr[2],rem_ip_addr[3],rem_udp_port);

7netbios_hdr=(NETBIOS_HDR*)netbios_rx_buf;

8netbios_name_hdr=(NETBIOS_NAME_HDR*)(netbios_hdr+1);

/*ifthepackeTIsaNetBIOSnamequeryquesTIon*/

9if(((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(“netbiosnamequeryquesTIon\r\n”);

/*decodetheNetBIOSname*/

10netbios_name_decoding((char*)(netbios_name_hdr->encname),netbios_name,sizeof(netbios_name));

printf(“nameis%s\r\n”,netbios_name);

/*ifthepacketisforus*/

11if(strcmp(netbios_name,NETBIOS_W5500_NAME)==0)

{

uint8ip_addr[4];

NETBIOS_RESP*resp=(NETBIOS_RESP*)netbios_tx_buf;

/*prepareNetBIOSheaderresponse*/

12resp->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);

resp->resp_hdr.questions=0;

resp->resp_hdr.answerRRs=htons(1);

resp->resp_hdr.authorityRRs=0;

resp->resp_hdr.additionalRRs=0;

/*prepareNetBIOSheaderdatas*/

memcpy(resp->resp_name.encname,netbios_name_hdr->encname,sizeof(netbios_name_hdr->encname));

resp->resp_name.nametype=netbios_name_hdr->nametype;

resp->resp_name.type=netbios_name_hdr->type;

resp->resp_name.cls=netbios_name_hdr->cls;

resp->resp_name.ttl=htonl(NETBIOS_NAME_TTL);

resp->resp_name.datalen=htons(sizeof(resp->resp_name.flags)+sizeof(resp->resp_name.addr));

resp->resp_name.flags=htons(NETB_NFLAG_NODETYPE_BNODE);

getSIPR(ip_addr);

memcpy(resp->resp_name.addr,ip_addr,4);

/*sendtheNetBIOSresponse*/

13sendto(NETBIOS_SOCK,(unsignedchar*)resp,sizeof(NETBIOS_RESP),rem_ip_addr,rem_udp_port);

printf(“sendresponse\r\n”);

}

}

}

break;

14caseSOCK_CLOSED:

close(NETBIOS_SOCK);

socket(NETBIOS_SOCK,Sn_MR_UDP,NETBIOS_PORT,0);

break;

default:

break;

}

}

主要代码解释:

第1、2段程序功能为通过SPI接口读取NBNSSocket寄存器状态,如果检测建立了UDP连接,并且收到数据则进行NBNS服务。第3段定义了NetBIOSname缓存区,Netbiosname长度为16。第4、5段定义了NetBIOS包头和其name部分结构体变量。第6段为读取137端口的UDP数据)netbios_rx_buf。接下来NBNS核心部分:

第7、8两段将接受缓存区数据对定义的包头进行赋值,第9,10段,判断数据NetBIOS包头是否为名字查询,如果是名字查询则进行名字解析。第11行进行NetBIOS名字进一步比较。比较一致后,第12段程序准备回复NetBIOS包头和内容。第13段,发送NetBIOS回复响应。第14段为检测到NBNSSocket为SOCK_CLOSED,则打开137端口的UDPSocket。

四实验测试

试验中,我们通过W5500EVB对NetBIOS的解析,并用浏览器直接访问设备名称,来实现对设备的远程访问,以达实验目的。下面就来看一下实验测试全过程。

基于W5500的NetBIOS应用实例

首先,打开串口调试助手,运行DHCP相关程序。可看到图5中所示,W5500EVB成功通过DHCP获得可用IP地址。

2.在DOS下,pingW5500EVB设备名:WIZNET5500,可看到如图6中,获取设备IP地址为:192.168.1.100。

基于W5500的NetBIOS应用实例

3.运行NetBIOS解析程序,在串口调试助手中看到解析过程,如图7所示:

基于W5500的NetBIOS应用实例

4.最后,我们在浏览器中输入要访问的设备名称:wiznet5500,可以看到顺利访问到设备中的内置网页,浏览到设备的配置信息。NetBIOS解析成功




工程师
2020-10-29 22:55:40     打赏
2楼

感谢分享


共2条 1/1 1 跳转至

回复

匿名不能发帖!请先 [ 登陆 注册 ]