1.1.3 NetBIOS编程基础(1)
NetBIOS是用于网络的基本输入/输出系统,是一个应用程序接口,用于源与目的地之间的交换,即能够支持计算机应用程序与设备通信时要用到的各种具有明确而简单的通信协议,必须用特殊的命令序列来调用NetBIOS。
在参考层次模型中,NetBIOS处于表示层和会话层之间,是参考模型的高层。因此其接口程序的应用在很大程度上(并且从本质上)与较低层次的各种活动隔离开。它支持IEEE 802.2的逻辑链路控制协议。现在NetBIOS正迅速地成为不同操作系统环境下普遍使用的通信平台,这些操作系统包括PC DOS、OS/2、Unix和Windows。
1. 处理过程
NetBIOS提供会话服务的建立过程如下。
(1) 建立会话
该过程类似于C/S模式中的连接建立过程,在此不再讨论。需注意的是,NetBIOS的Client方是采用Call呼叫对方,而不是Connect。
(2) 传送数据
因为NetBIOS的会话服务是以双工流的形式实现的,因此会话双方(或多方)均可以同时发送或接收数据,而无须考虑对方的状态。
NetBIOS的命令发送支持两种模式,一种是send,其数据块最大长度为64KB,且位于连续的内存空间;另一种则是chain send命令。顾名思义,它是以多个缓冲区(两个)提供发送数据的,因此该命令一次可最大传送64KB×2的数据。与此对应的NetBIOS接收命令有如下3种。
receive:它以建立会话时所获得的唯一标识对方的会话号为句柄接收数据。
receive any:该命令可从一个name建立的多个会话上取得数据。
receive any-any:它可从任何会话上接收任何数据。
(3) 终止会话
当会话一方发出hang up命令后,即可终止对话,并释放相应的资源。
2. NetBIOS命令
NetBIOS作为一种接口,拥有许多实现某些功能的接口。最为常用的NetBIOS命令如表1-3所示。
表1-3 NetBIOS命令一览表
类 别 |
命 令 |
命令代码 |
功能说明 |
|
wait |
no wait |
|||
名字管理 |
add name add group name delete name |
30h 36h 31h |
b0h b6h b1h |
增加本地唯一名 增加本地小组名 删除本地名字 |
数据报服务 |
send datagram send broadcast receive datagram receive broadcast |
20h 22h 21h 23h |
a0h a2h a2h a3h |
发送数据报 发送广播数据报 接收数据报 接收广播数据报 |
会话服务 |
call listen send chain send send no-ack chain send no-ack receive receive any hang up |
10h 11h 14h 17h 71h 72h 15h 16h 12h |
90h 91h 94h 97h f1h f2h 95h 96h 92h |
呼叫建立会话 侦听建立会话 按会话号发送数据 按会话号发送数据,不应答 发送双缓冲数据,不应答 按会话号接收数据 从任意会话号上接收数据 拆除当前会话 |
一般命令 |
repeat adapter status session status cancel unlink |
32h 33h 34h 35h 70h |
b3h b4h |
初始化网络适配器 读取网络适配器状态 按名字读取当前会话状态 撤消一个NetBIOS命令 断开远程连接 |
1.1.3 NetBIOS编程基础(2)
3. NetBIOS名字解析
由于NetBIOS是一种与TCP/IP独立发展的标准,虽然它可以使用TCP/IP作为传输协议,但是由于概念上的不同,它并没有利用TCP/IP提供的全部能力,而是使用自己的方式来完成类似的工作。其中最大的区别在于名字解析方式上。NetBIOS具备自己独立的名字解析概念和能力,因此它使用的名字解析方式就与TCP/IP 中标准解析方式--DNS不同。在必须经过NetBIOS名字解析获得相应的IP地址之后,NetBIOS会话就可以建立在普通TCP连接的基础上了。所以在NetBIOS中,名字解析是NetBIOS会话与普通TCP 连接最大的不同之处。
NetBIOS名字解析与DNS名字解析的最大不同在于NetBIOS是动态的,计算机需要首先注册自己的名字,然后才能解析到该名字。动态解析虽然带来很大的方便性,但却复杂和低效得多,因此只能用于小范围的局域网中。
每个NetBIOS的名字可以多达16个字符,第16个字符用来标识输入名字时使用的程序类型。当NetBIOS的计算机进行通信时,它必须基于NetBIOS名字,而不能基于IP地址。一个NetBIOS服务程序必须首先注册自己的NetBIOS名字,而一个应用程序则需要查询所需要的NetBIOS名字。例如,每台Windows计算机在启动之后初始化网络时就使用所配置的计算机名字来初始化其使用的NetBIOS名字。
(1) NetBIOS名字解析方式
从NetBIOS名字查找相应的节点地址(TCP/IP协议中为IP地址)有如下几种不同的查找方式。
本地广播:在本地网络上发送广播,通过广播某设备的NetBIOS名字,查找其对应的IP地址。广播方式也能用于注册自己的NetBIOS名字,例如,一台计算机可以通过广播本机的名字,向其他计算机宣告自己使用了这个NetBIOS名字。
缓冲:每个支持NetBIOS的计算机中,维护一个NetBIOS名字和相应IP地址的列表,这些对应的名字都有一定的生存期,以便能及时更新。
NetBIOS名字服务器:使用一个名字服务器来提供名字与IP之间的解析任务,这个NetBIOS名字服务器被称为NBNS(NetBIOS Name Server),Microsoft实现的NBNS名字服务器为WINS(Windows Internet Name Service)。NetBIOS计算机首先要向NBNS登记自己的NetBIOS名字,完成名字的注册过程。
预定义文件lmhosts:Microsoft Windows能通过查找存放在本地文件lmhosts中的数据,来识别网络上NetBIOS名字和IP的关系,这个方式不是NetBIOS名字识别的标准,但它是Microsoft的实现方式,因此是一种事实标准。
通过DNS和hosts文件解析:DNS服务器和本地hosts文件中存放的数据是用于标准TCP/IP协议中名字和IP之间转换使用的方式,但使用其他方式查找不出对应的节点地址时,Microsoft Windows中通常也能通过标准的TCP/IP名字解析方式,进行名字和IP的转换。同样这也不是NetBIOS的标准,而是Microsoft的扩展。
从上述5种NetBIOS识别方式,以及其中的不同的名字注册方式出发,可以实现不同的组合方式,从而构成了不同的名字识别策略。在NetBIOS标准中,将使用不同名字识别策略的模式称为不同的NetBIOS节点类型。
B-node:通过广播方式来进行注册和识别NetBIOS名字。对于IP协议上的Net BIOS,就需要基于UDP进行广播,在小网络上这种方式工作得很好,但当网络增大时,就会被使用路由器将大网络分割为几个小网。在一般情况下路由器不转发广播数据,广播包仅发送到本地网络。虽然可以配置路由器进行b-node广播转发,但是这将使UDP广播产生大量的无用网络数据,且名字注册和解析的难度也增加了。因此对于较大的网络,这种方式不可取。
P-node(peer-to-peer):对等方式能为识别名字提供非常有效的方法,它使用 NetBIOS名字服务器进行名字的注册登记和名字识别。因此对于每个NetBIOS计算机,必须指定同样的NBNS服务器的IP地址。这样在NBNS服务器停机或更改了设置(如IP地址等)的情况下,名字解析不能完成,就不能进行NetBIOS通信。当然NetBIOS计算机可以配置为使用多个NBNS服务器,以便在其中一个出现问题时使用备份的服务器。
M-node(Mixed):为了正确解析NetBIOS名字,最好综合使用广播和名字服务器的方式,这样的名字识别是一个复合的过程。M-node首先通过B-node广播方式进行名字识别过程,当广播方式失败之后,再使用P-node方式进行查询。
H-Node(Hybrid):H-node模式也是一种复合模式,它与M-node不同的地方是查找的顺序不同。H-node先查找NBNS名字服务器,然后再使用广播方式进行查询。
Windows中实际使用的名字识别方式是对标准H-node方式的扩展,Windows系列的计算机将首先检查缓存中的内容,然后再查看WINS服务器,之后进行广播,然后将查找lmhosts文件,以及通过hosts和DNS进行查找。实际进行NetBIOS识别是一个复杂的过程,主要就是由于NetBIOS是一个动态的名字解析方式,每一台计算机都必须注册自身。
(2) NetBIOS名字识别的过程
与DNS不同,NetBIOS名字使用动态方式进行管理。DNS数据是静态的,增加和删除DNS名字需要管理员手工更改配置文件。但NetBIOS要求计算机在网络上自动注册其名字,计算机停机之后占用的名字会被释放,这个过程不需要管理员干预。因为它需要额外的网络数据以完成名字登记等过程,使得它不适合像Internet这样的大型网络。
NetBIOS名字识别需要经过如下3个步骤。
① 名字注册:在NetBIOS启动时,计算机向整个网络声明占用了一个NetBIOS名字,如果已经有其他计算机占用了这个名字,这台计算机就会收到错误信息。注册是通过向网络广播声明信息或向NetBIOS名字服务器登记的方式来实现的。
② 名字解析:通过广播或查询NetBIOS名字服务器来解析一个NetBIOS名字。此外还可以通过lmhosts文件和DNS辅助解析名字。
1.1.3 NetBIOS编程基础(3)
③ 名字删除:系统关机或提供的工作站服务结束时,会删除其占用的NetBIOS名。
通过NetBIOS名字和共享的目录名,就能够定位Windows计算机上的资源。Microsoft使用UNC的形式来确定一个网络资源的位置,一个UNC以双反斜线开始,接下来是提供资源计算机的NetBIOS名字,然后是该台计算机上提供资源的共享名,接下来就是下面的目录和文件名。如\\ntserver\share\files。
因此使用一个资源的命令格式如下所示:
- C:\> net use f: \\ntserver\share
- C:\> f:
- F:\>
(3) 名字服务器的工作原理
由于B-node广播会在网络上产生大量的信息流,尤其是在网络是由多个子网构成的时候,而使用路由器本来就是要隔离广播信息,可是为了进行名字解析,就不得不转发B-node广播信息包,这就达不到缩减无用网络流量的目的。
使用名字服务器进行解析就能避免这个问题,客户通过对名字服务器进行查询而非广播,信息流就不必传播到各个子网上,就能减少广播数据,减轻网络的负担,节省带宽,并且能有效地提高名字解析的速度及准确性。
实际存在的Windows网络甚至很少利用名字服务器进行名字解析,这就使得这些网络名字解析存在很大问题,常常会出现不同计算机的网络邻居列表不同,根本原因就是广播方式是没有保证的,必须转向名字服务器方式才能解决名字解析问题。
当普通NetBIOS计算机和NBNS服务器进行通信时,有如下4个不同的通信过程。
名字注册:每台NetBIOS计算机启动时,都在名字服务器上注册。这样就保持了数据库的自动更新,并具备动态更新的特性。名字服务器将返回确认信息,以及这个名字的生存期TTL。如果客户要求的名字已经被占用了,服务器就查询占用这个名字的客户是否还在网络上,以判断这个名字是否可以再次被使用。这种情况主要发生在Windows计算机死机后重新登记的过程中,因为此时在计算机死机之前,它在名字服务器中登记的名字还存在,如果名字服务器简单地拒绝提供 名字,那么这个计算机就无法再次获得自己的名字。只有在真正发生冲突的情况下,客户的名字注册才会失败。
名字更新:由于每个名字都存在一个生存期TTL,那么当经历了这个TTL一半的时候,客户会向服务器进行更新请求,刷新服务器上的TTL设置。
名字释放:客户停机时会与服务器通信释放其占用的NetBIOS名字,其名字TTL超时也会使得服务器释放这个名字。
名字识别:客户可以向NBNS服务器发送查询名字的请求,进行名字解析。
在某些情况下,客户没有设置支持名字服务器,或者使用的客户软件还不支持名字服务器进行解析,可以通过设置一个 WINS代理,由它来在广播数据和查询名字服务器之间进行转换,它可以帮助客户注册并回应客户的广播查询。
4. 何谓NetBEUI
NetBEUI是网络操作系统使用的NetBIOS协议的加强版本。它规范了在NetBIOS中未标准化的传输帧,还加了额外的功能。传输层驱动器经常被Microsoft LAN Manager(微软局域网管理器)使用。
NetBEUI执行OSI LLC2协议。NetBEUI是原始的PC网络协议和IBM为LanManager(局域网管理器)服务器设计的接口。本协议稍后被微软采用,作为它们的网络产品的标准。它规定了高层软件通过NetBIOS帧协议发送、接收信息的方法。本协议运行在标准802.2数据链协议层上。
5. NetBIOS范围
NetBIOS范围ID为建立在TCP/IP(叫做NBT)模块上的NetBIOS提供额外的命名服务。NetBIOS范围ID的主要目的是隔离单个网络上的NetBIOS通信和那些有相同NetBIOS范围ID的节点。NetBIOS范围ID是附加在NetBIOS名称上的字符串。两个主机上的 NetBIOS范围ID必须匹配,否则两主机无法通信。NetBIOS范围ID允许计算机使用相同的计算机名,不同的范围ID。范围ID是NetBIOS名称的一部分,使名称唯一。
6. NetBIOS控制块
NetBIOS控制块(NCB)是所有NetBIOS应用程序访问NetBIOS服务时都要用到的一个程序设计结构,并且是唯一的一个。设备驱动程序也使用类似的结构。NetBIOS控制块的定义结构如下:
- typedef struct _NCB {
- BYTE ncb_command;
- BYTE ncb_retcode;
- BYTE ncb_lsn;
- BYTE ncb_num;
- DWORD ncb_buffer;
- WORD ncb_length;
- BYTE ncb_callName[16];
- BYTE ncb_name[16];
- BYTE ncb_rto;
- BYTE ncb_sto;
- BYTE ncb_post;
- BYTE ncb_lana_num;
- BYTE ncb_cmd_cplt;
- BYTE ncb_reserved[14];
- } NCB, *PNCB;