如何用NETBIOS将网络连接断掉? API函数WNetCancelConnection、WNetCancelConnection2可用于断开网络连接。用NETBIOS断开连接,不懂。 解决方案 » 免费领取超大流量手机卡,每月29元包185G流量+100分钟通话, 中国电信官方发货 to ilang(中雨)能否具体点,给出源码行吗?再次感谢!!! 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; ncbRoc 我不赞同QQ,我一定反对360。 这个问题不得不提了,想破了我的头,还是解决不了 本来这个时候不该郁闷,还是郁闷了,散分100 TFileStream.Write的问题 如何与MDI的子窗体通信 delphi错误提示分析! 如何设置EXCEL一个单元格内的字为不同的字体和颜色 如何绑定若干条SQL语句为一个事务? 当表有用Trigger修改其他表时,保存会出现错误!!! 如何动态使用构件和控件 谁知道microsoft studio.net和windows.net的系列号? 在delphi中怎样搜索aa目录所在的路径?
能否具体点,给出源码行吗?再次感谢!!!
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; ncbRoc