線上訂房服務-台灣趴趴狗聯合訂房中心
發文 回覆 瀏覽次數:1824
推到 Plurk!
推到 Facebook!

Delphi實現NetBIOS廣播收發

 
jackkcg
站務副站長


發表:891
回覆:1050
積分:848
註冊:2002-03-23

發送簡訊給我
#1 引用回覆 回覆 發表時間:2002-10-25 13:37:18 IP:61.221.xxx.xxx 未訂閱
此為轉貼資料    Delphi實現NetBIOS廣播收發      NetBIOS網路協定對於很多讀者來說可能比較陌生,但其實它是由IBM開發的一個很古老的協定,當年在LAN上也風光一時。說它老,其實也不過10年光景,IT業的發展實在是太快。由於NetBIOS不具備路由功能,也就是說它的資料包無法跨網段傳輸,因此在廣域網、城域網大行其道的今天,它已退居配角。如果你有心的話,能夠發現在Window95 / 98的網路協定中仍然保留著NetBIOS,不過它已經改名叫NetBEUI(NetBIOS擴展用戶介面),是NetBIOS的Microsoft改進版。另外在TCP/IP以及IPX/SPX協定中,也依然保留了對NetBIOS的支援,只要查看網路協定屬性中的高級,就能看到?用NetBIOS的選項。     之所以這樣是有原因的。NetBIOS協定短小精悍,非常適用於小型局域網,特別是一些對即時性要求較高的網路環境。NetBIOS的廣播功能由於有開發使用方便、系統開銷小的優點,所以在很多場合仍然被大量使用。筆者由於工作需要,在一個航太測控軟體的編制中就使用了NetBIOS廣播功能。     我原以?這是件很簡單的工作,因?WIN32API中提供了一個Netbios函數,裏面封裝了所有函數和資料結構,用起來很方便,在BC和VC下都如此。可是由於這次是使用流行的Delphi作編譯器,卻遇到了意想不到的麻煩:號稱全面移植WIN32API的Delphi中偏偏沒有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+}        file://聲明一個NCB記錄指標。        PNCB=^NCB;       file://聲明一個後處理常式的過程類型。        POST=procedure(var ncbR:PNCB);       file://以下是NCB記錄,教訓1:將上面的編譯選項置?{$A+}以取消資料對齊。如果在廣播中有浮點數的話,資料對齊會讓你大吃苦頭!我已經有過慘痛教訓!:(        NCB=record        ncb_command:UCHAR;        ncb_retcode:UCHAR;        ncb_lsn:UCHAR;        ncb_num:UCHAR;        ncb_buffer:PCHAR;        ncb_length:WORD;        ncb_callname:array [1..16] of UCHAR;        ncb_name:array [1..16] of UCHAR;        ncb_rto:UCHAR;        ncb_sto:UCHAR;        ncb_post:POST;        ncb_lana_num:UCHAR;        ncb_cmd_cplt:UCHAR;        ncb_reserve:array [1..10] of UCHAR;        ncb_event:HANDLE;        end;       file://聲明自己的Netbios函數。教訓2:一定要使用pascal調用規範,否則,嘿嘿!!       function NetbiosSR(ncbX:PNCB):UCHAR;pascal;       file://初始化NCB。       procedure InitNCB(var ncbY:PNCB);       file://後處理常式,注意使用遠指標。       procedure postrout(var ncbR:PNCB);stdcall;far;       var        char_buffer:array[0..511]of UCHAR;        int_buffer:array[1..512]of Byte;     implementation        file://調用系統的Netbios。dll中的Netbios函數標號是6。Delphi搜索外部文件的順序是當前目錄→系統目錄→其他目錄,別忘了保證存在Netbios.dll。        function NetbiosSR(ncbX:PNCB):UCHAR;external       ‘netbios'' index 6;        procedure InitNCB(var ncbY:PNCB);        var        x:integer;        begin        ncbY.ncb_command:=0;      ncbY.ncb_retcode:=0;        ncbY.ncb_lsn:=0;        ncbY.ncb_num:=0;        ncbY.ncb_length:=512; file://資料緩衝長度,最大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;       file://後處理常式的作用是當接收到廣播消息時,立即向相應視窗發送消息。我在這裏偷了點懶,以廣播方式發送一個計時器消息。如果你願意可以向指定視窗發送自定義消息,這樣要複雜一些。     首先,要把指定視窗的控制碼傳遞給後臺處理常式。通常這是做不到的,但可以利用一些技巧做到。在NCB記錄後面緊挨著聲明一個控制碼類型,然後把指定視窗的控制碼賦值給它的實例變數;這樣控制碼變數的位址與NCB是連續的。在後處理中通過指標或彙編語句將ncbR的位址移到最後一個位元組+1,就是視窗控制碼的起始位址。明白嗎?至於自定義消息,需要重新編譯連接庫,限於篇幅我就不囉嗦了,有興趣的可以自己嘗試。    procedure postrout(var ncbR:PNCB);     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}        file://消息處理過程,注意消息巨集要與後處理中的一致。      procedure post_main(var Message:TMessage);message WM_TIMER;     public        {Public declarations}      end;       var        main: Tmain;        ncbname:UCHAR;        ncbRock:PNCB;        post_add:POST;     implementation       {$R *.DFM}{$A-}{$I-}     /////////主窗口建立過程/////////       procedure Tmain.FormCreate(Sender: TObject);       var        ret:UCHAR;        i,x,y:integer;        p:single;       begin        new(ncbRock);        randomize();i:=0;        FillChar(char_buffer,sizeof(char_buffer),0);        post_add:=@postrout;        file://取後處理常式的位址。        ncbRock.ncb_buffer:=@char_buffer; file://取資料緩衝區的位址。        InitNCB(ncbRock);        ret:=9;        ncbname:=random(100);        ncbRock.ncb_name[1]:=ncbname;        ncbRock.ncb_command:=$30;        file://加名,ret?0加名成功。        while ((i<10)and(ret<>0)) do begin ret:=netbiosSR(ncbRock); i:=i+1; end; if ret<>0 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; file://非同步接收方式字。 ncbRock.ncb_event:=0; ncbRock.ncb_length:=512; ret:=netbiosSR(ncbRock); end; end; ///////////廣播消息處理過程///// procedure Tmain.post_main(var Message:TMessage); var x:integer; ret:UCHAR; begin file://取出資料緩衝區的內容 for x:=0 to 511 do int_buffer[x+1]:=char_buffer[x]; ////以下可以進行資料處理//// file://重新打開非同步接受。 ncbRock.ncb_post:=post_add; ncbRock.ncb_command:=$a3; ncbRock.ncb_event:=0; ncbRock.ncb_length:=512; ret:=netbiosSR(ncbRock); end; end. 注:廣播發送非常簡單,不再詳述。上述程式經過一年運行完全可靠。另外,經過改造可以將其改?LAN下的聊天程式。
------
**********************************************************
哈哈&兵燹
最會的2大絕招 這個不會與那個也不會 哈哈哈 粉好

Delphi K.Top的K.Top分兩個字解釋Top代表尖端的意思,希望本討論區能提供Delphi的尖端新知
K.表Knowlege 知識,就是本站的標語:Open our mind
系統時間:2024-04-20 4:48:45
聯絡我們 | Delphi K.Top討論版
本站聲明
1. 本論壇為無營利行為之開放平台,所有文章都是由網友自行張貼,如牽涉到法律糾紛一切與本站無關。
2. 假如網友發表之內容涉及侵權,而損及您的利益,請立即通知版主刪除。
3. 請勿批評中華民國元首及政府或批評各政黨,是藍是綠本站無權干涉,但這裡不是政治性論壇!