Nb30.pas NetBIOS 3.0

来源:互联网 发布:mac版cad2016字体库 编辑:程序博客网 时间:2024/05/29 19:38

NetBIOS中所用的函数声明、常数等等均是在头文件nb30.h内定义的,nb30.h中一些类型在wtypes.h中定义,
因此一般在网络程序开始的include语句中将wtypes.h放在nb30.h之前。另外,使用NetBIOS还须连接库netapi32.lib。

调用NetBIOS函数时,可使用NetBIOS中提供的一个唯一的函数调用:

uRetCode = netbios(&ncb);

入口参数:    &ncb为指向一网络控制块(NCB)的指针。在调用NetBIOS函数前要先预置好该NCB结构中的一些有关字段;

出口返回:   返回码uRetCode正常时应为0,返回的具体结果会包含在NCB结构的一些字段中。


NetBIOS编程时要用到的一些结构有:

1. NCB结构:

在该NCB结构中,包含了为执行一个NetBIOS命令相应需预先准备(在调用前)或命令执行结果(在调用后)的全部信息,


typedef struct _NCB{

CHAR  ncb_command; 用于指定要执行的NetBIOS命令, 一些常见的NetBIOS命令如附表所示。
                   命令可以有非异步(也称等待方式)和异步(也称非等待方式)两种方式执行:
                  将命令名和常量ASYNCH进行OR操作后的结果放入ncb_command则置为异步(非等待)方式;
                  若将命令名放入ncb_command则置为非异步(等待)方式。           
         在采用等待方式执行时,NetBIOS函数调用要等到该命令操作完成之后才返回执行下一条语句。
         如果采用非等待(异步)方式执行,可以在调用NetBIOS前设置ncb_post(后处理程序地址)或设置ncb_event(触发事件对象句柄),
         让NetBIOS在完成命令后自动唤醒该后处理程序或触发相关事件,在采用异步方式时,NetBIOS函数调用当场立即返回,
         执行下一条语句,并且带回“立即返回代码”ncb_retcode,而当命令执行完时,又返回一个“最终返回代码”ncb_cmd_cplt,
         //你的程序可以根据这两个代码确定该命令是否成功执行。

CHAR  ncb_retcode;   用于指定操作的立即返回代码,若返回值为NRC_GOODRET(即0),表示无立即差错

CHAR  ncb_lsn;   本地会话号。在使用面向连接的会话方式通信时,建立会话时,
         首先,两个站分别使用增加名字命令NCBADDNAME或增加组名命令NCBADDGRNAME增加本站名字,
         然后,一个站须发出NCBLISTEN命令,另一站发出NCBCALL命令,每一方成功执行完命令,
         都会在NCB中返回一个本地会话号ncb_lsn,此后,两个站使用NCBSEND、NCBRECV命令发送、接收数据时,
         都要在命令调用前在NCB中的ncb_lsn字段赋值引用该本地会话号

CHAR   ncb_num;  本地名字号。在使用无连接的数据报方式通信时,每次须先使用增加名字命令NCBADDNAME或增加组名命令NCBADDGRNAME增加本站名,
        这时,NetBIOS函数都会返回这个新增加的名字一个名字号。此后,两个站使用NCBDGSEND、NCBDGRECV命令发送、接收数据报时,
        都要在命令调用前在NCB中的ncb_num字段赋值引用该本地名字号

PCHAR  ncb_buffer; 指向数据缓冲区的指针。发送时,在NetBIOS函数调用前,该缓冲区中须放置要发送的实际数据;
          接收时,为NetBIOS函数调用后返回的接收数据;对其他命令来说,如NCBENUM,缓冲区中是NetBIOS函数调用后返回的预定义的结构LANA_ENUM;
          对NCBSTAT命令来说,缓冲区里就是NetBIOS函数调用命令执行后逻辑网卡返回的统计结果

WORD    ncb_length;  指定缓冲区的长度,以字节数为单位,发送时为发送数据的字节数;接收时NetBIOS会将该值设为实际收到的字节数,
                     若指定的缓冲区不够大,NetBIOS会返回 NRC_BUFLEND错误

CHAR   ncb_callname[NCBNAMSZ];  用于指定远方机器应用程序用的名字

CHAR   ncb_name[NCBNAMSZ];     用于指定本方机器应用程序用的名字

CHAR  ncb_rto;  规定接收操作时的会话超时时间(以0.5秒为单位)

CHAR  ncb_sto;  规定发送操作时的会话超时时间(以0.5秒为单位)

void (CALLBACK *ncb_post) (struct _NCB *);  若使用异步命令(即非等待方式时),操作完成后调用的后处理程序地址

CHAR  ncb_lana_num;  指定LAN Adapter逻辑网卡号

CHAR  ncb_cmd_cplt;  完成操作后的最终返回代码,操作成功,正常返回NRC_GOODRET(即0);
                      若用异步操作,操作正进行期间NetBIOS会将这个值设为NRC_PENDING

CHAR  ncb_reserve[10]; 保留,必须为0;

HANDLE  ncb_event;  事件对象的句柄。当一个异步命令被接受时,事件对象被置为不发信号状态,
        当该异步命令完成时,事件对象被置为发信号状态,当NetBIOS函数返回非0值
        时也会发信号给事件。ncb_command为非异步(等待)方式时或ncb_post非0时,该ncb_event应为0。

}NCB, *PNCB;


2.LANA_ENUM结构:

nb30.h中还定义了另外一个很重要的结构LANA_ENUM,当主机中有两块以上逻辑网卡(一物理网卡绑定某一协议为一逻辑网卡)时,
使用NCB命令NCBENUM后(该命令只能在Windows NT/2000/XP中使用),
该结构中会含有返回的逻辑网卡个数及每个逻辑网卡号,该结构的定义如下:

typedef struct  LANA_ENUM {
        CHAR  length;//系统中含有的逻辑网卡个数
        CHAR  lana [MAX_LANA];//数组中放各个逻辑网卡号
} LANA_ENUM, *PLANA_ENUM;

其中: lana [MAX_LANA]定义了一个存放所有逻辑网卡信息的数组,
       length表示该数组的长度,即为本机所带逻辑网卡的个数。


3. 网卡结构ASTAT和网卡状态结构ADAPTER_STATUS

(1)网卡结构ASTAT,其中使用了网卡状态结构ADAPTER_STATUS:
typedef struct

{

         ADAPTER_STATUS  adapt;
         NAME_BUFFER     NameBuff[30];

} ASTAT;

(2)网卡状态结构ADAPTER_STATUS:

typedef struct _ADAPTER_STATUS {

    CHAR   adapter_address[6];   //网卡MAC地址
    CHAR   rev_major;
    CHAR   reserved0;
    CHAR   adapter_type;
    UCHAR   rev_minor;
    WORD    duration;
    WORD    frmr_recv;
    WORD    frmr_xmit;
    WORD    iframe_recv_err;
    WORD    xmit_aborts;
    DWORD   xmit_success;
    DWORD   recv_success;
    WORD    iframe_xmit_err;
    WORD    recv_buff_unavail;
    WORD    t1_timeouts;
    WORD    ti_timeouts;
    DWORD   reserved1;
    WORD    free_ncbs;
    WORD    max_cfg_ncbs;
    WORD    max_ncbs;
    WORD    xmit_buf_unavail;
    WORD    max_dgram_size;
    WORD    pending_sess;
    WORD    max_cfg_sess;
    WORD    max_sess;
    WORD    max_sess_pkt_size;
    WORD    name_count;

} ADAPTER_STATUS, *PADAPTER_STATUS;


使用NetBIOS获取网卡MAC地址的编程提示:


1. 在调用netbios NCBASTAT命令前,我们可将指向ADAPTER_STATUS结构的指针值赋给缓冲区指针ncb.ncb_buffer,

ASTAT  Adapter;

ncb.ncb_buffer = (unsigned char *) &Adapter;  //两个指针指向同一个地方
        ncb.ncb_length = sizeof(Adapter);            // 设置ncb_buffer缓冲区长度


这样在执行NCBASTAT命令后,由于ncb.ncb_buffer指针所指的缓冲区中为命令执行后逻辑网卡返回的统计结果
(其中包含MAC网卡地址、一组有关网络负荷和差错的统计数字、网卡所在工作站的名字表以及每个名字对应的状态信息等),
我们使用与其同一地址的ADAPTER_STATUS结构的adapter_address[6]字段便可取出其中的网卡地址。


2. 由于ncb_command字段用于指定要执行的netbios命令,在执行一个netbios函数调用前应先赋值ncb_command字段,
      另外,还要设置NCB中一些与该命令相关的字段:


var
  ncb: TNCB;
  status: TAdapterStatus;
  lanenum: TLanaEnum;
  mystr:string;
   //对每块逻辑网卡进行初始化(复位)
  procedure ResetAdapter(num: char);
  begin
    fillchar(ncb, sizeof(ncb), 0);
    ncb.ncb_command := char(NCBRESET);
    ncb.ncb_lana_num := num;
    Netbios(@ncb);
  end;
var
  i, n: integer;
  lanNum: char;
  address: record
    part1: Longint;
    part2: Word;
  end absolute status;
begin
  Result := '';
  fillchar(ncb, sizeof(ncb), 0); //NCB结构清零
  ncb.ncb_command := char(NCBENUM); //该结构包含系统中的逻辑网卡数目及每个逻辑网卡号
  ncb.ncb_buffer := @lanenum;
  ncb.ncb_length := sizeof(lanenum);
  Netbios(@ncb);
  if lanenum.length = #0 then  //读出返回的逻辑网卡个数
    exit;
  for n := 0 to High(lanenum.lana) do
  begin
    lanNum := lanenum.lana[c];
    ResetAdapter(lanNum);//对每块逻辑网卡进行初始化(复位)
    fillchar(ncb, sizeof(ncb), 0);
    ncb.ncb_command := char(NCBASTAT);
    ncb.ncb_lana_num := lanNum;
    ncb.ncb_callname[0] := '*';// ncb_callname 中要设置netbios调用时对方使用的名字,*表示不限定,这里用来表示要对本机统计信息。

    ncb.ncb_buffer := @status;
    ncb.ncb_length := sizeof(status);
    Netbios(@ncb);

    ResetAdapter(lanNum);
    for i := 0 to 5 do
    begin
      mystr := mystr + inttoHex(integer(status.adapter_address[i]), 2);
      if (i < 5) then
        mystr := mystr + '-';
    end;
      mystr := mystr + #13;
  end;

  Result:=mystr;
 
end;