×

基于W5500的NetBIOS应用实例资料下载

消耗积分:2 | 格式:pdf | 大小:443.92KB | 2021-04-24

分享资料个

一 实例背景最近一个做智能家居的朋友面临这样的一个烦恼,他想让用户通过智能手机在家里方便地控制家居设备,又想让用户免除下载安装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: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;1state = getSn_SR(NETBIOS_SOCK);switch(state){case SOCK_UDP:2if((len=getSn_RX_RSR(NETBIOS_SOCK))>0){unsigned char rem_ip_addr[4];uint16 rem_udp_port;3char netbios_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);/* if the packet is a NetBIOS name query question */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(“netbios name query question\r\n”);/* decode the NetBIOS name */10netbios_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 */11if (strcmp(netbios_name, NETBIOS_W5500_NAME) == 0){uint8 ip_addr[4];NETBIOS_RESP *resp = (NETBIOS_RESP*)netbios_tx_buf;/* prepare NetBIOS header response */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;/* prepare NetBIOS header datas */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);/* send the NetBIOS response */13sendto(NETBIOS_SOCK, (unsigned char*)resp, sizeof(NETBIOS_RESP), rem_ip_addr, rem_udp_port);printf(“send response\r\n”);}}}break;14case SOCK_CLOSED:close(NETBIOS_SOCK);socket(NETBIOS_SOCK,Sn_MR_UDP,NETBIOS_PORT,0);break;default:break;}}主要代码解释:第1、2段程序功能为通过SPI接口读取NBNS Socket寄存器状态,如果检测建立了UDP连接,并且收到数据则进行NBNS服务。第3段定义了NetBIOS name缓存区,Netbios name长度为16。第4、5段定义了NetBIOS包头和其name部分结构体变量。第6段为读取137端口的UDP数据)netbios_rx_buf。接下来NBNS核心部分:第7、8两段将接受缓存区数据对定义的包头进行赋值,第9,10段,判断数据NetBIOS包头是否为名字查询,如果是名字查询则进行名字解析。第11行进行NetBIOS名字进一步比较。比较一致后,第12段程序准备回复NetBIOS包头和内容。第13段,发送NetBIOS回复响应。第14段为检测到NBNS Socket为SOCK_CLOSED,则打开137端口的UDP Socket。四实验测试试验中,我们通过W5500EVB对NetBIOS的解析,并用浏览器直接访问设备名称,来实现对设备的远程访问,以达实验目的。下面就来看一下实验测试全过程。首先,打开串口调试助手,运行DHCP相关程序。可看到图5中所示,W5500EVB成功通过DHCP获得可用IP地址。2. 在DOS下,ping W5500EVB设备名:WIZNET5500,可看到如图6中,获取设备IP地址为:192.168.1.100。

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

评论(0)
发评论

下载排行榜

全部0条评论

快来发表一下你的评论吧 !

'+ '

'+ '

'+ ''+ '
'+ ''+ ''+ '
'+ ''+ '' ); $.get('/article/vipdownload/aid/'+webid,function(data){ if(data.code ==5){ $(pop_this).attr('href',"/login/index.html"); return false } if(data.code == 2){ //跳转到VIP升级页面 window.location.href="//m.lene-v.com/vip/index?aid=" + webid return false } //是会员 if (data.code > 0) { $('body').append(htmlSetNormalDownload); var getWidth=$("#poplayer").width(); $("#poplayer").css("margin-left","-"+getWidth/2+"px"); $('#tips').html(data.msg) $('.download_confirm').click(function(){ $('#dialog').remove(); }) } else { var down_url = $('#vipdownload').attr('data-url'); isBindAnalysisForm(pop_this, down_url, 1) } }); }); //是否开通VIP $.get('/article/vipdownload/aid/'+webid,function(data){ if(data.code == 2 || data.code ==5){ //跳转到VIP升级页面 $('#vipdownload>span').text("开通VIP 免费下载") return false }else{ // 待续费 if(data.code == 3) { vipExpiredInfo.ifVipExpired = true vipExpiredInfo.vipExpiredDate = data.data.endoftime } $('#vipdownload .icon-vip-tips').remove() $('#vipdownload>span').text("VIP免积分下载") } }); }).on("click",".download_cancel",function(){ $('#dialog').remove(); }) var setWeixinShare={};//定义默认的微信分享信息,页面如果要自定义分享,直接更改此变量即可 if(window.navigator.userAgent.toLowerCase().match(/MicroMessenger/i) == 'micromessenger'){ var d={ title:'基于W5500的NetBIOS应用实例资料下载',//标题 desc:$('[name=description]').attr("content"), //描述 imgUrl:'https://'+location.host+'/static/images/ele-logo.png',// 分享图标,默认是logo link:'',//链接 type:'',// 分享类型,music、video或link,不填默认为link dataUrl:'',//如果type是music或video,则要提供数据链接,默认为空 success:'', // 用户确认分享后执行的回调函数 cancel:''// 用户取消分享后执行的回调函数 } setWeixinShare=$.extend(d,setWeixinShare); $.ajax({ url:"//www.lene-v.com/app/wechat/index.php?s=Home/ShareConfig/index", data:"share_url="+encodeURIComponent(location.href)+"&format=jsonp&domain=m", type:'get', dataType:'jsonp', success:function(res){ if(res.status!="successed"){ return false; } $.getScript('https://res.wx.qq.com/open/js/jweixin-1.0.0.js',function(result,status){ if(status!="success"){ return false; } var getWxCfg=res.data; wx.config({ //debug: true, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。 appId:getWxCfg.appId, // 必填,公众号的唯一标识 timestamp:getWxCfg.timestamp, // 必填,生成签名的时间戳 nonceStr:getWxCfg.nonceStr, // 必填,生成签名的随机串 signature:getWxCfg.signature,// 必填,签名,见附录1 jsApiList:['onMenuShareTimeline','onMenuShareAppMessage','onMenuShareQQ','onMenuShareWeibo','onMenuShareQZone'] // 必填,需要使用的JS接口列表,所有JS接口列表见附录2 }); wx.ready(function(){ //获取“分享到朋友圈”按钮点击状态及自定义分享内容接口 wx.onMenuShareTimeline({ title: setWeixinShare.title, // 分享标题 link: setWeixinShare.link, // 分享链接 imgUrl: setWeixinShare.imgUrl, // 分享图标 success: function () { setWeixinShare.success; // 用户确认分享后执行的回调函数 }, cancel: function () { setWeixinShare.cancel; // 用户取消分享后执行的回调函数 } }); //获取“分享给朋友”按钮点击状态及自定义分享内容接口 wx.onMenuShareAppMessage({ title: setWeixinShare.title, // 分享标题 desc: setWeixinShare.desc, // 分享描述 link: setWeixinShare.link, // 分享链接 imgUrl: setWeixinShare.imgUrl, // 分享图标 type: setWeixinShare.type, // 分享类型,music、video或link,不填默认为link dataUrl: setWeixinShare.dataUrl, // 如果type是music或video,则要提供数据链接,默认为空 success: function () { setWeixinShare.success; // 用户确认分享后执行的回调函数 }, cancel: function () { setWeixinShare.cancel; // 用户取消分享后执行的回调函数 } }); //获取“分享到QQ”按钮点击状态及自定义分享内容接口 wx.onMenuShareQQ({ title: setWeixinShare.title, // 分享标题 desc: setWeixinShare.desc, // 分享描述 link: setWeixinShare.link, // 分享链接 imgUrl: setWeixinShare.imgUrl, // 分享图标 success: function () { setWeixinShare.success; // 用户确认分享后执行的回调函数 }, cancel: function () { setWeixinShare.cancel; // 用户取消分享后执行的回调函数 } }); //获取“分享到腾讯微博”按钮点击状态及自定义分享内容接口 wx.onMenuShareWeibo({ title: setWeixinShare.title, // 分享标题 desc: setWeixinShare.desc, // 分享描述 link: setWeixinShare.link, // 分享链接 imgUrl: setWeixinShare.imgUrl, // 分享图标 success: function () { setWeixinShare.success; // 用户确认分享后执行的回调函数 }, cancel: function () { setWeixinShare.cancel; // 用户取消分享后执行的回调函数 } }); //获取“分享到QQ空间”按钮点击状态及自定义分享内容接口 wx.onMenuShareQZone({ title: setWeixinShare.title, // 分享标题 desc: setWeixinShare.desc, // 分享描述 link: setWeixinShare.link, // 分享链接 imgUrl: setWeixinShare.imgUrl, // 分享图标 success: function () { setWeixinShare.success; // 用户确认分享后执行的回调函数 }, cancel: function () { setWeixinShare.cancel; // 用户取消分享后执行的回调函数 } }); }); }); } }); } function openX_ad(posterid, htmlid, width, height) { if ($(htmlid).length > 0) { var randomnumber = Math.random(); var now_url = encodeURIComponent(window.location.href); var ga = document.createElement('iframe'); ga.src = 'https://www1.elecfans.com/www/delivery/myafr.php?target=_blank&cb=' + randomnumber + '&zoneid=' + posterid+'&prefer='+now_url; ga.width = width; ga.height = height; ga.frameBorder = 0; ga.scrolling = 'no'; var s = $(htmlid).append(ga); } } openX_ad(828, '#berry-300', 300, 250);