NetBIOS广播收发

NetBIOS网络协议对于很多读者来说可能比较陌生,但其实它是由IBM开发的一个很古老的协议,当年在LAN上也风光一时。说它老,其实也不过10年光景,IT业的发展实在是太快。由于NetBIOS不具备路由功能,也就是说它的数据包无法跨网段传输,因此在广域网、城域网大行其道的今天,它已退居配角。如果你有心的话,能够发现在Window9598的网络协议中仍然保留着NetBIOS,不过它已经改名叫NetBEUI(NetBIOS扩展用户接口),是NetBIOS的Microsoft改进版。另外在TCPIP以及IPXSPX协议中,也依然保留了对NetBIOS的支持,只要查看网络协议属性中的高级,就能看到启用NetBIOS的选项。  之所以这样是有原因的。NetBIOS协议短小精悍,非常适用于小型局域网,特别是一些对实时性要求较高的网络环境。NetBIOS的广播功能由于有开发使用方便、系统开销小的优点,所以在很多场合仍然被大量使用。笔者由于工作需要,在一个航天测控软件的编制中就使用了NetBIOS广播功能。  我原以为这是件很简单的工作,因为WIN32API中提供了一个Netbios函数,里面封装了所有函数和数据结构,用起来很方便,在BC和VC下都如此。可是由于这次是使用流行的Delphi作编译器,却遇到了意想不到的麻烦号称全面移植WIN32API的Dlphi中偏偏没有Netbios函数!这下顿时让我方寸大乱。怎么办总不能从底层干起吧而且时间也不允许。在冷静下来之后,我忽然想到,既然WIN95支持NetBIOS,那么系统就一定会提供DLL支持,编译器本身是没有底层支持的。于是我在机器中搜索,果然,在SYSTEM目录下有一个Netbios.dll,用快速查看将其打开,在导出表部分显示如下}  
导出表  序数 入口 名称  
0000 00001a37 NetbiosAddthd  
0001 000019eb NetbiosDelete  
0002 00001a96 NetbiosDelthd  
0003 000019b1 NetbiosInitialize  
0004 0000186b PostRoutineCaller  
0005 0000102e _Netbios  

注意到那个0005号_Netbios导出函数了吗那就是我需要的!经过紧张的试验调试,证明它和WIN32API手册上的Netbios完全一样。剩下的工作就比较简单了,定义一个NCB(Netbios控制块)记录,将NCB数据结构封装在里面;声明一个后处理例程以及消息处理过程,以完成广播数据的接收和发送。有关NCB数据结构的详细内容以及NetBIOS广播的原理,限于篇幅我就省略了。需要的朋友可以查看BC或VC的Help或相关书籍。下面是有关的Delphi源代码。  
Netbios单元  
unit netbios;  
interface  
uses windows,messages,Forms,SysUtils;  
type  {$X+}{$A+}   //声明一个NCB记录指针。  
PNCB=&NCB;  //声明一个后处理例程的过程类型。  
POST=procedure(var ncbRPNCB);   

//以下是NCB记录,教训1将上面的编译选项置为{$A+}以取消数据对齐。如果在广播中有浮点数的话,数据对齐会让你大吃苦头!我已经有过//惨痛教训!(  
NCB=record  
ncb_command:UCHAR;  
ncb_retcode:UCHAR;  
ncb_lsn:UCHAR;  
ncb_num:UCHAR;  
ncb_buffer:PCHAR;  
ncb_length:WORD;  
ncb_callnamearray [1..16] of UCHAR;  
ncb_namearray [1..16] of UCHAR;  
ncb_rto:UCHAR;  
ncb_sto"UCHAR;  
ncb_post"POST;  
ncb_lana_num:UCHAR;  
ncb_cmd_cplt:UCHAR;  
ncb_reservearray [1..10] of UCHAR;  
ncb_event:HANDLE;  
end;  
{声明自己的Netbios函数。教训2一定要使用pascal调用规范,否则,嘿嘿!!} 
function NetbiosSR(ncbXPNCB)UCHAR;pascal;  //初始化NCB。  
procedure InitNCB(var ncbYPNCB);  //后处理例程,注意使用远指针。  
procedure postrout(var ncbRPNCB);stdcall;far;  
var
 char_bufferarray[0..511]of UCHAR;  
 int_bufferarray[1..512]of Byte;  
implementation  

{调用系统的Netbios。dll中的Netbios函数标号是6。Delphi搜索外部文件的顺序是当前目录→系统目录→其他目录,别忘了保证存在Netbios.dll。}  
function NetbiosSR(ncbXPNCB)UCHAR;external 'netbios' index 6;  
procedure InitNCB(var ncbYPNCB);  
var  
 xinteger;  
begin  
 ncbY.ncb_command=0;  
 ncbY.ncb_retcode=0;  
 ncbY.ncb_lsn=0;  
 ncbY.ncb_num=0;  
 ncbY.ncb_length=512; 数据缓冲长度,最大512B。  
 for x=1 to 16 do  
 begin  
  ncbY.ncb_callname[x]=0;  
  ncbY.ncb_name[x]=0;  
  end;  
  ncbY.ncb_rto=0;  
  ncbY.ncb_sto=0;  
 ncbY.ncb_lana_num=0;  
 ncbY.ncb_cmd_cplt=0;  
 for x=1 to 10 do  
 ncbY.ncb_reserve[x]=0;  
 ncbY.ncb_event=0;  
end;  
{
后处理例程的作用是当接收到广播消息时,立即向相应窗口发送消息。我在这里偷了点懒,以广播方式发送一个定时器消息。如果你愿意可以向指定窗口发送自定义消息,这样要复杂一些。首先,要把指定窗口的句柄传递给后处理例程。通常这是做不到的,但可以利用一些技巧做到。在NCB记录后面紧挨着声明一个句柄类型,然后把指定窗口的句柄赋值给它的实例变量;这样句柄变量的地址与NCB是连续的。在后处理中通过指针或汇编语句将ncbR的地址移到最后一个字节+1,就是窗口句柄的起始地址。明白吗至于自定义消息,需要重新编译连接库,限于篇幅我就不罗嗦了,有兴趣的可以自己尝试。} 

procedure postrout(var ncbRPNCB);  
begin   
 sendMessage(wnd_BROADCAST,WM_TIMER,0,0);  
end;  
end.  

//窗口单元  
unit broadcast;  
interface  
uses  
Windows,Messages,SysUtils,Classes,Graphics,Controls,Forms,Dialogs,netbios;  
type   Tmain=class(TForm)  
private   {Private declarations}   //消息处理过程,注意消息宏要与后处理中的一致。  
procedure post_main(var MessageTMessage);message WM_TIMER;  
public   {Public declarations}
end;  
var
 main Tmain;  
 ncbnameUCHAR;  
 ncbRockPNCB;  
 post_addPOST;  
 implementation  
{$R *.DFM}{$A-}{$I-}  

//主窗口建立过程  
procedure Tmain.FormCreate(Sender TObject);  
var  
 retUCHAR;  
 i,x,yinteger;  
 psingle;  
begin  
 new(ncbRock);  
 randomize();i=0;  
 FillChar(char_buffer,sizeof(char_buffer),0);  
post_add=@postrout;   //取后处理例程的地址。  
 ncbRock.ncb_buffer=@char_buffer; //取数据缓冲区的地址。  
 InitNCB(ncbRock);  
 ret=9;  
 ncbname=random(100);  
 ncbRock.ncb_name[1]=ncbname;  
 ncbRock.ncb_command=$30;   //加名,ret为0加名成功。  
 while ((i10)and(ret0)) do  
 begin  
  ret=netbiosSR(ncbRock);  
  i=i+1;  
 end;  
 if ret0 then  
 begin  
 for i=1 to 20 do  
  messagebeep(-1);  
  MessageDlg('网络通信无法实现!您需要关闭程序重新运行.',mtWarning,[mbOk],0);  
 end else
 if ret=0 then  
 begin  
  ncbRock.ncb_post=post_add;  
  ncbRock.ncb_command=$a3; 异步接收方式字。  
  ncbRock.ncb_event=0;  
  ncbRock.ncb_length=512;  
  ret=netbiosSR(ncbRock);  
 end;  
end;  
//广播消息处理过程  
procedure Tmain.post_main(var MessageTMessage);  
var  
 x:integer;  
 ret:UCHAR;  
begin   //取出数据缓冲区的内容  
 for x=0 to 511 do  
  int_buffer[x+1]=char_buffer[x];  
  //以下可以进行数据处理   重新打开异步接受。  
  ncbRock.ncb_post=post_add;  
  ncbRock.ncb_command=$a3;  
  ncbRock.ncb_event=0;  
  ncbRock.ncb_length=512;  
  ret=netbiosSR(ncbRock);  
 end;  
end.  

//注广播发送非常简单,不再详述。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值