NetBIOS是網絡基本的輸入/輸出系統,是一個應用於程序接口,用於數據源與目的地之間的數據交換。即能夠訪問支持計算機應用程序和設備通信時要用到的各種服務,具有明確而簡單的通信協議,必須用特殊的命令序列來調用NetBIOS服務。
首先我們來了解一下NetBIOS的基本知識。
一.NetBIOS 的基礎
1。在網絡層次中,NetBIOS是處於表示層和會話層之間,是參考模型的高層。因此其接口程序的應用在很大程度上並且從本質上與較低層次的各種活動隔離開。它支持IEEE802.2 的邏輯鏈路控制(LLC)協議。現在NetBIOS正迅速地成為不同操作系統環境下普遍使用的數據通信平台,這些操作系統包括PC DOS,OS/2,UNIX 和Windows。
2。NetBIOS的出現是在1984年8月IBM PC的網絡適配器中,是由Sytek公司為IBM設計的。它采用寬帶同軸電纜,提供每秒2MB的數據傳輸突發率,使用了流行的工業標准CSMA/CD(多訪問載波偵聽/載波檢測)作為訪問協議,這種協議首次出現在IEEE 802.3 以太網標准中。
3。NetBIOS的應用服務:NetBIOS提供四種應用服務,它們分別為:命名支持,數據報支持,會話支持和通用命令。
(1).命名支持:每個NetBIOS 網絡積適配器在網絡中都使用一個或多個網絡名來標識自己,以區別於其他的網絡適配器。網絡名由16個字符組成。
(2).數據報支持:當一個適配器在網絡中激活後,在計算機上的應用程序就可以用NetBIOS與駐留在同一個或不同計算機上的其他應用通信。它們之間的應用通信可以使用數據報來進行。
數據報是一條短信息,它的長度隨NetBIOS實現方法的不同而不同,不能保證數據的正確傳輸。也不接收來自接收方的指示,如:在存在,未加電或不接收數據報,這樣 在網絡發生故障時,發出的數據報可能不會被任何計算機接收到。
數據報有兩種類:廣播型和定向型。廣播型是完全不區分接收者的數據報,可以使用NetBIOS的Send Broadcast Datagram命令來發送數據,接收方可調用NetBIOS Receive Broadcaset Datagram命令來接收數據。定向型是指定數據報接收者的組名,任何一方都可以調用NetBIOS Send Datagram命令發送數據,接收方可以調用NetBIOS Receive Datagram命令來接收發送過來的數據。
(3).會話支持:在NetBIOS應用通信中的第二種形式是會話通信了,它支持可以在兩個應用程序之間創建一個可靠的雙向數據通信連接,並能保持較長時間。這種連接有時也稱為虛電路。相互通信的應用可以駐留在同一台計算機上(本地會話)或駐留在不同的計算機上(遠程會話)。
會話通信比數據報通信的優點有:對於每個被發送的信息,發送前能得知對方接收准備情況,而數據報通信只提供信息的發送狀態。
可以使用NetBIOS的Listen命令來創建會話,Listen命令引用NetBIOS命令表中的一個名字。另一端則使NetBIOS Call 命令,Call命令要用到其NetBIOS命名表中的名字,這個名字必須與另一端的的應用程序所用的名字相匹配,這樣兩邊的名字相匹配是兩個應用創建會話的依據,在Listen 命令和 Call 命令執行完後,就建立會話了。注意的是:首先調用 Listen命令,然後再調用 Call 命令,這個順序不能顛倒。
會話創建後,每個客戶端都收到一個會話已創建的指示,得到一個字節的無符號返回值,表示會話與適配器之間的聯。創建會話後,每個客戶端都可以調用NetBIOS的Send和Receive命令來傳輸和接收數。
(4).通用命令:NetBIOS的通用命令提供了五項NetBIOS服務,分別是:Reset(復位適配器),Adapter Status(顯示適配器狀態),Cancel and Unlink(撤消及斷開命令),Find Name(匹配名字)和 Trace(跟蹤命令)。
1).Reset 命令強迫適配器進入初始化狀態,終止所有的會話,並刪除NetBIOS 命名表中除永久節點名以外的所有名字。
2).Adapter Status 命令用來查詢NetBIOS適配器,以獲取有關操作信息,如:發現LAN 錯誤數和適配器NetBIOS命名表,用於知道遠程計算機和適配器是否都被掛起,還是只有計算機被掛起。這是對遠程適配器的狀態進行查詢的一個很好的實現方法。
3).Cancel and Unlink:Cancel 命令是使應用程序結束尚未執行完的命令。Unlink命令是允許RPL引導的PC Network LAN 適配器,從RPL服務器上脫開,它只對基本適配器有效,通常返回一個 0 值,表明請求成功。4).Find Name 命令用於找出一個由Find Name 命令指定的符號名的適配器,在多個適配器共用一個組名時,它們都可以同時都應答,但是只有一個應答將返回給發出請求的應用端。
5).Trace 命令將激活對所有發向NetBIOS 接口的命令進行跟蹤,其基本用途是為診斷程序提供支持。
4.NetBIOS命令的調用:
在應用程序中調用 NetBIOS 命令之前,將內存的一個64 字節區域先清空為 0 ,這樣防止內存原有的數據導致NetBIOS 命令結束時,NetBIOS 錯誤地進入其他內存區域。應用程序使用這個區域創建一個 NetBIOS 控制塊(NCB)。調用 NetBIOS 命令時,要根據命令的要求,填充控制塊的域,所以如果沒有正確填充這些NCB域,會導致用戶計算機運行的掛起,這樣會破壞整個系統。
NetBIOS 中利用的一個函數就是 Netbios(),此函數用於解說和執行指定的信息控制塊(NCB)。函數定義如下:UCHAR Netbios(PNCB pncb);參數 pncb 用於描述網絡控制塊結構的指針。
NCB 結構的定義如下:
typeddf struct_NCB{
UCHAR ncb_command; //命令碼
UCHAR ncb_retcode; //返回碼
UCHAR ncb_lsn; //本地會話編碼
UCHAR ncb_num; //數據報
ADD NAME (增加名)表入口
PUCHAR ncb_buffer; //信息緩沖區
WORD ncb_length; //信息緩沖區長度
UCHAR ncb_callname[NCBNAMSZ]; //CALL 的遠程系統名
UCHAR neb_name[NCBNAMSZ]; //本地適配器網絡名
UCHAR ncb_rto; //以 1/2s 為單位的接收超時UCHAR ncb_sto; //以 1/2s 為單位的發送超時void(*ncb_post)(struct_NCB*); //POST 例程指針
UCHAR ncb_lana_num; //執行命令的網絡適配器編號
UCHAR ncb_cmd_cplt; //0XFF 命令掛起,否則命令結束
UCHAR ncb_reserve[10]; //保留值
HANDLE ncb_event; //事件句柄
}NCB;
NCB 命令域包含用於期望操作的 NetBIOS 的命令碼,如果命令碼的高價位是 0 ,NetBIOS 接收這個請求,並且當命令執行完成後,返回到應用程序,在這裡這叫等待選擇。每次只能有一個等待選擇命令被掛起.雖然Reset,Cancel和Unlink 這些命令能保證執行完畢,但是其他一些命令僅僅在某些情況下才會結束。如果這樣一個命令不結束,則NetBIOS 將不返回,並且計算機因為 NetBIOS 在等待結束的無限循環中而浪費資源。如要避免發生這樣的情況,應用程序可以將除Reset,Cancel和Unlink 命令外所有命令的命令域的高價位設置為 1 ,這叫不等待選擇。 NCB 返回碼最終會包含命令的最終返回碼值,如在命令結束後,其值為 0 ,則表示該命令成功地結束。否則,表明出現了錯誤。
NCB 的本地會話編碼域包含著與一條命令相聯系的本地會話編號。NCB 的名字編號域包含著與一條命令相聯的 NetBIOS 命令表格中的名字編號。
NCB 的緩沖區域是一個指向信息緩沖區的指針。NCB 的緩沖區長度域記錄了由NCB 的緩沖區域所指向的緩沖區的大小。NCB 的調用名域為16字節長,它包含著同該請求相關的一個遠程名。
NCB 的本地名域包含著與請求相關的一個本地名。
NCB 的接受超時域與CALL 和 LISTEN 命令一起使用,它以 1/2s的時間間隔為單位。NCB 的發送超時域與CALL 和 LISTEN 命令一起使用,它以 1/2s的時間間隔為單位。
現把 Netbios() 函數的返回值介紹如下:
00h : 成功地完成,成功返回
01h : 無效的緩沖區
03h : 無效的命令
05h : 命令超時
06h : 不完整地接收消息
07h : 本地No-Ack命令失敗
08h : 無效的本地會話
09h : 沒有可使用的資源
0Ah : 會話已關閉
0Bh : 命令已撤消
0Dh : 本地NetBIOS命名表中名字重復
0Eh : NetBIOS命名表滿
0Fh : 名字具有活動會話,現被撤消登記
11h : NetBIOS 本地會話表滿了
12h : 沒有掛起的Listen 命令,所有拒絕斷開會話
13h : 非法名字編號
14h : 不能找到被調用名字或無回答
15h : 找不到命令,或不能把*號或00h指定ncb_name的首字節,或名字已被撤消而不能再使用
17h : 名字已被刪除18h : 會話非正常結束
19h : 檢測到名字沖突
1Ah : 不兼容的遠程設備
21h : 接口忙
22h : 掛起的命令太多
23h : 在ncb_lana_num域中無效的編號
24h : 產生取消時,命令已完成
25h : 字節組名命令指定了保留名字
26h : 命令不能被撤消
30h : 被另一個進程定義了名字
34h : NetBIOS環境未被定義
35h : 所用的操作系統資源用盡
36h : 超出最大應用個數
37h : NetBIOS無可以使用的SAP
38h : 無可以使用的請求資源
40h : 系統錯誤
41h : 檢測到遠程適配器的熱載波
42h : 檢測到本地適配器的熱載波
43h : 未檢測到載波
4Eh : 狀態位12、14、或15被置位的時間超過 1 min
4Fh : 狀態位8--11中的一個或多個被置位
50h--F6h: 適配器發生故障
F7h : 隱式DIR-INITIALIZE錯誤
F8h : 隱式DIR-OPEN-ADAPTER 錯誤
F9h : IBM LAN支持程序內部錯誤
FAh : 適配器檢查
FBh : NetBIOS 程序未被裝入PC
FCh : DIR-OPEN-ADAPTER 或 DIR-OPEN-SAP失敗
FDh : 不期望關閉適配器
FFh : 命令掛起狀態
為了更好地解說NetBIOS 的編程,現設計一個用 NetBIOS 來編寫獲取網絡適配器信息的程序
二、創建程序例子
在C++Builder 5.0 中選擇File / New ,打開“New Items”對話框,在對框中選擇Consol Wizard.隨後彈出“Consol Application Wizard”對話框,在Windows Type 中選擇Consol,在ExecutionType中選擇EXE,然後選擇Finish,生成一個新的控制台應用程序。
//“Project1.cpp”源代碼如下:
#pragma hdrstop
#include <condefs.h>;
#include <windows.h>;
#include <stdio.h>;
typedef struct _ASTAT
{
ADAPTER_STATUS adapt;
NAME_BUFFER NameBuffer[30];
} ASTAT, *PASTAT;ASTAT Adapter;//自定義復位適配器函數
bool ClearAdapter(NCB ncb);
//---------------------------------------------------------------------------
//#pragma argsused
int main()
{
NCB ncb;
UCHAR uRetCode;//先復位網絡適配器ClearAdapter(ncb);memset(&;ncb,0,sizeof(ncb));//命令碼為顯示適配器狀態
ncb.ncb_command=NCBASTAT;
ncb.ncb_lana_num=0;
strcpy((char *)ncb.ncb_callname,"* ");
ncb.ncb_buffer=(unsigned char *) &;Adapter;
ncb.ncb_length=sizeof(Adapter);
uRetCode=Netbios(&;ncb);
printf("The NCBASTAT returned code is OX%x\n",uRetCode);if(uRetCode==0)
{
printf( "The Ethernet Number is: %02x_%02x_%02x_%02x_%02x_%02x\n",
Adapter.adapt.adapter_address[0],
Adapter.adapt.adapter_address[1],
Adapter.adapt.adapter_address[2],
Adapter.adapt.adapter_address[3],
Adapter.adapt.adapter_address[4],
Adapter.adapt.adapter_address[5] );
if(Adapter.adapt.adapter_type==0xFF)
printf("The adapter is Token Ring adapter.\n");
else if(Adapter.adapt.adapter_type==0xFE)
printf("The adapter is Ethernet adapter.\n");printf("The software-release level is %d.%d\n",Adapter.adapt.rev_major,Adapter.adapt.rev_minor);
printf("The number of names in the local names table is %d\n",Adapter.adapt.name_count);
for(int i=0;i<;Adapter.adapt.name_count;i++)
printf("%s\n",Adapter.NameBuffer[i].name);
}//注意下面程序代碼故意出錯誤
char Remote[16]="202.112.87.221";//先復位網絡適配器
ClearAdapter(ncb);
memset(&;ncb,0,sizeof(ncb));//命令碼為發送數據
ncb.ncb_command=NCBSEND;
ncb.ncb_lana_num=0;
ncb.ncb_lsn=4;
ncb.ncb_sto=2;
strcpy(ncb.ncb_callname,Remote);
//strcpy((char *)ncb.ncb_callname,"* ");
ncb.ncb_buffer=(unsigned char *) &;Adapter;
ncb.ncb_length=sizeof(Adapter);
uRetCode=Netbios(&;ncb);
printf("The NCBASTAT returned code is OX%x\n",uRetCode);
printf("The number of FRMR frames received is %d\n",Adapter.adapt.frmr_recv);
printf("The number of FRMR frames transmitted is %d\n",Adapter.adapt.frmr_xmit);getchar();
return 0;
}
//---------------------------------------------------------------------------
//復位網絡適配器 bool ClearAdapter(NCB ncb)
{
memset(&;ncb,0,sizeof(ncb));
ncb.ncb_command=NCBRESET;
ncb.ncb_lana_num=0;
Netbios(&;ncb);
return true;
}
以上實例利用網絡基本輸入/輸出系統NetBIOS創建了一個能獲取主機 MAC (網絡適配器)信息及其他一些信息的應用程序。由於作者水平有限,有不當之處請涼解。本文希望能起到拋磚引玉的作用。