给你一段代码,你参考。是别人的代码。
整套软件可以发给你,应该可以得到你要的。
{
(c)2001 zw84611
this unit do the samce thing as dos command "nbtstat -a ip".
This is not a vcl component, it's just a unit, needn't install.
}
unit Nbtstat;
interface
uses
Windows, Messages, SysUtils, Classes, Controls, Dialogs, WinSock, ComCtrls, Forms;
const
WM_SOCK = WM_USER + 1; //自定义windows消息
//UDPPORT = 6767; //设定UDP端口号
NBTPORT = 137; //NAME_SERVICE_UDP_PORT 137 (decimal) (RFC1002)
type
TNbt = class(TComponent)
private
s: TSocket;
addr: TSockAddr;
FSockAddrIn : TSockAddrIn; //利用消息实时获知UDP消息
FHandle: HWnd; //非可视构件消息处理使用
procedure ReadData(var Message: TMessage); //message WM_SOCK;
procedure RecvNbMsg(buffer: array of byte;len:integer;IP:string);
procedure SendData(b:array of byte;IP:string);
public
wait_time: integer;
StartIP, EndIP: string;
StatusString: string;
MyListView: TListView;
OnEndEvent: TNotifyEvent;
OnSendEvent: TNotifyEvent;
OnAddNodeEvent: TNotifyEvent;
//RootTreeNode: TTreeNode;
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
procedure Start;
procedure Stop;
procedure Pause;
procedure Restart;
end;
TSendDataThread=class(TThread)
private
IP, IP1, IP2: string;
protected
procedure Execute; override;
procedure GetIP;
procedure Send;
procedure OnExit;
end;
var
Nbt: TNbt;
B1,B2: array [0..3]of byte;
SendDataThread: TSendDataThread;
WAIT_ACK_EVENT: Thandle;
exit_nbt_thread: boolean;
implementation
//uses FmxUtils; // IsLegalIP
{
function IsLegalIP(IP:string):boolean;
begin
if Longword(inet_addr(pchar(IP)))=INADDR_NONE then
begin
result:=false;
exit;
end
else result:=true;
end;
}
{
procedure GetAddrByte(IP:string;var B:array of byte);
var i,j:integer;
s:string;
begin
s:='';
j:=0;
IP:=IP+'.';
for i:=1 to length(IP)do
begin
if IP<>'.' then s:=s+IP
else
begin
B[j]:=byte(strtoint(s));
inc(j);
s:='';
end;
end;
end;
}
procedure TSendDataThread.Send;
{
RFC1002: " PROTOCOL STANDARD FOR A NetBIOS SERVICE ON A TCP/UDP TRANSPORT:
DETAILED SPECIFICATIONS "
4.2.17. NODE STATUS REQUEST
1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| NAME_TRN_ID |0| 0x0 |0|0|0|0|0 0|B| 0x0 |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| 0x0001 | 0x0000 |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| 0x0000 | 0x0000 |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| |
/ QUESTION_NAME /
| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| NBSTAT (0x0021) | IN (0x0001) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
}
const NbtstatPacket:array[0..49]of byte
=($0,$0,$0,$0,$0,$1,
$0,$0,$0,$0,$0,$0,$20,$43,$4b,
$41,$41,$41,$41,$41,$41,$41,$41,
$41,$41,$41,$41,$41,$41,$41,$41,
$41,$41,$41,$41,$41,$41,$41,$41,
$41,$41,$41,$41,$41,$41,$0,$0,$21,$0,$1);
begin
Nbt.StatusString := '正在测试:' + IP;
if assigned(Nbt.OnSendEvent) then Nbt.OnSendEvent(nil);
Nbt.SendData(NbtstatPacket, IP);
end;
procedure TSendDataThread.GetIP;
begin
IP1 := Nbt.StartIP;
IP2 := Nbt.EndIP;
end;
procedure TSendDataThread.OnExit;
begin
if assigned(Nbt.OnEndEvent) then Nbt.OnEndEvent(nil);
end;
procedure TSendDataThread.Execute;
var
nIP1, nIP2, i: dword;
begin
Synchronize(GetIP);
{if (not IsLegalIP(IP1))or(not IsLegalIP(IP2)) then
begin
ShowMessage('Illegal IP address!');
exit;
end; }
//GetAddrByte(IP,B1);
//GetAddrByte(IP2,B2);
nIP1 := ntohl(inet_addr(pchar(IP1)));
nIP2 := ntohl(inet_addr(pchar(IP2)));
for i := nIP1 to nIP2 do
begin
if exit_nbt_thread then
begin
Synchronize(OnExit);
exit;
end;
//去掉x.x.x.0或x.x.x.255的地址。
if (((i - 255) mod 256)=0)or((i mod 256)=0) then continue;
IP := inet_ntoa(in_addr(htonl(i)));
Synchronize(Send);
WaitForSingleObject(WAIT_ACK_EVENT,Nbt.wait_time);
ResetEvent(WAIT_ACK_EVENT);
end;
{
repeat
if exit_thread then
begin
Synchronize(OnExit);
exit;
end;
IP:=format('%d.%d.%d.%d',[B1[0],B1[1],B1[2],B1[3]]);
Synchronize(Send);
WaitForSingleObject(WAIT_ACK_EVENT,Nbt.wait_time);
ResetEvent(WAIT_ACK_EVENT);
if(B1[2]<=B2[2]) then
begin
if(B1[3]<B2[3]) then inc(B1[3])
else if((B1[2]<B2[2]) and (B1[3]<255))then inc(B1[3])
else if((B1[2]<B2[2]) and (B1[3]=255)) then
begin
B1[3]:=1;
inc(B1[2]);
end;
end
else break;
if((B1[3]>=B2[3]) and (B1[2]>=B2[2])) then break;
until ((B1[2]=255));// or (B1[3]=255));
}
Synchronize(OnExit);
end;
constructor TNbt.Create(AOwner: TComponent);
var
TempWSAData: TWSAData;
//optval: integer;
begin
inherited Create(AOwner);
FHandle := AllocateHWnd(ReadData); //attention here.
// 初始化SOCKET
if WSAStartup($101, TempWSAData)=1 then
showmessage('StartUp Error!');
s := Socket(AF_INET, SOCK_DGRAM, 0);
if (s = INVALID_SOCKET) then //Socket创建失败
begin
ShowMessage(inttostr(WSAGetLastError())+' Socket创建失败');
CloseSocket(s);
end;
//本机SockAddr绑定
addr.sin_family := AF_INET;
addr.sin_addr.S_addr := INADDR_ANY;
//addr.sin_port := htons(UDPPORT);
if Bind(s, addr, sizeof(addr)) <> 0 then
begin
showmessage('bind fail');
end;
WSAAsyncSelect(s, FHandle , WM_SOCK, FD_READ);
//对方SockAddrIn设定
FSockAddrIn.SIn_Family := AF_INET;
FSockAddrIn.SIn_Port := htons(NBTPORT);
WAIT_ACK_EVENT:=CreateEvent(nil,true,false,pchar('WAIT_ACK'));
//ResetEvent(WAIT_ACK_EVENT);
wait_time:=100;
end;
destructor TNbt.Destroy;
begin
CloseSocket(s);
WSACleanup();
DeallocateHWnd(FHandle);
inherited Destroy;
end;
procedure TNbt.RecvNbMsg(buffer: array of byte;len:integer;IP:string);
var
str:string;
i,j,pos,name_num: integer;
item : TListItem;
begin
item:=MyListView.Items.Insert(0);
item.Caption := IP;
for i:=0 to 4 do item.SubItems.Add(''); // attention: we do like item.SubItems[3]:=str;
{
RFC1002: " PROTOCOL STANDARD FOR A NetBIOS SERVICE ON A TCP/UDP TRANSPORT:
DETAILED SPECIFICATIONS "
4.2.18. NODE STATUS RESPONSE
1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| NAME_TRN_ID |1| 0x0 |1|0|0|0|0 0|0| 0x0 |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| 0x0000 | 0x0001 |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| 0x0000 | 0x0000 |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| |
/ RR_NAME /
| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| NBSTAT (0x0021) | IN (0x0001) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| 0x00000000 |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| RDLENGTH | NUM_NAMES | |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +
| |
+ +
/ NODE_NAME ARRAY /
+ +
| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| |
+ +
/ STATISTICS /
+ +
| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
The NODE_NAME ARRAY is an array of zero or more NUM_NAMES entries
of NODE_NAME records. Each NODE_NAME entry represents an active
name in the same NetBIOS scope as the requesting name in the
local name table of the responder. RR_NAME is the requesting
name.
NODE_NAME Entry:
1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| |
+--- ---+
| |
+--- NETBIOS FORMAT NAME ---+
| |
+--- ---+
| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| NAME_FLAGS |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
The NAME_FLAGS field:
1 1 1 1 1 1
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
| G | ONT |DRG|CNF|ACT|PRM| RESERVED |
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
The NAME_FLAGS field is defined as:
Symbol Bit(s) Description:
RESERVED 7-15 Reserved for future use. Must be zero (0).
PRM 6 Permanent Name Flag. If one (1) then entry
is for the permanent node name. Flag is zero
(0) for all other names.
ACT 5 Active Name Flag. All entries have this flag
set to one (1).
CNF 4 Conflict Flag. If one (1) then name on this
node is in conflict.
DRG 3 Deregister Flag. If one (1) then this name
is in the process of being deleted.
ONT 1,2 Owner Node Type:
00 = B node
01 = P node
10 = M node
11 = Reserved for future use
G 0 Group Name Flag.
If one (1) then the name is a GROUP NetBIOS
name.
If zero (0) then it is a UNIQUE NetBIOS name.
STATISTICS Field of the NODE STATUS RESPONSE:
1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| UNIT_ID (Unique unit ID) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| UNIT_ID,continued | JUMPERS | TEST_RESULT |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| VERSION_NUMBER | PERIOD_OF_STATISTICS |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| NUMBER_OF_CRCs | NUMBER_ALIGNMENT_ERRORS |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| NUMBER_OF_COLLISIONS | NUMBER_SEND_ABORTS |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| NUMBER_GOOD_SENDS |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| NUMBER_GOOD_RECEIVES |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| NUMBER_RETRANSMITS | NUMBER_NO_RESOURCE_CONDITIONS |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| NUMBER_FREE_COMMAND_BLOCKS | TOTAL_NUMBER_COMMAND_BLOCKS |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|MAX_TOTAL_NUMBER_COMMAND_BLOCKS| NUMBER_PENDING_SESSIONS |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| MAX_NUMBER_PENDING_SESSIONS | MAX_TOTAL_SESSIONS_POSSIBLE |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| SESSION_DATA_PACKET_SIZE |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
}
name_num:=0;
for i:=1 to len do
begin
if((buffer=$21)and(buffer[i+1]=$00)and(buffer[i+2]=$01))
then
begin
name_num:=buffer[i+9];
break;
end;
end;
if name_num=0 then exit;
pos:=i+10;
str:='';
for i:=pos to (pos+18*name_num-1) do
begin
if (((i-pos)mod 18) =0) then
begin
for j:=0 to 14 do
begin
if trim(char(buffer[i+j]))='' then buffer[i+j]:=ord(' ');
str:=str+char(buffer[i+j]);
end;
if (buffer[i+16] and $80)=$80 then
begin
if buffer[i+15]=$0 then item.SubItems[0]:=str;
str:=str+format('<%x>',[buffer[i+15]]);
str:=str+'<GROUP>';
end
else
begin
if buffer[i+15]=$20 then item.SubItems[1]:=str
else
if buffer[i+15]=$3 then item.SubItems[2]:=str;
str:=str+format('<%x>',[buffer[i+15]]);
str:=str+'<UNIQUE>';
end;
//ListBox1.Items.Add(str);
str:='';
end;
end;
for i:=0 to 5 do
begin
str:=str+format('%.2x.',[buffer[i+pos+18*name_num]]);
end;
delete(str,length(str),1);
item.SubItems[3]:=str;
//----------------------------------------------------
if assigned(OnAddNodeEvent) then OnAddNodeEvent(TObject(IP));
end;
procedure TNbt.ReadData(var Message: TMessage);
var
buffer: Array [1..500] of byte;
flen,len: integer;
Event: word;
IP:string;
begin
if Message.msg<>WM_SOCK then exit;
//Windows.Beep(2000,200);
flen:=sizeof(FSockAddrIn);
FSockAddrIn.SIn_Family := AF_INET;
FSockAddrIn.SIn_Port := htons(NBTPORT);
Event := WSAGetSelectEvent(Message.LParam);
if Event = FD_READ then
begin
len := recvfrom(s, buffer, sizeof(buffer), 0, FSockAddrIn, flen);
if len> 0 then
begin
//FSockAddrIn.sin_addr.S_un_b.s_b1
with FSockAddrIn.sin_addr.S_un_b
do IP:=format('%d.%d.%d.%d',[ord(s_b1),ord(s_b2),ord(s_b3),ord(s_b4)]);
RecvNbMsg(buffer,len,IP);
end;
SetEvent(WAIT_ACK_EVENT);
end;
end;
procedure TNbt.SendData(b:array of byte;IP:string);
var
len: integer;
begin
FSockAddrIn.SIn_Addr.S_addr := inet_addr(pchar(IP));
FSockAddrIn.SIn_Family := AF_INET;
FSockAddrIn.SIn_Port := htons(NBTPORT);
len := sendto(s, b[0],50, 0, FSockAddrIn, sizeof(FSockAddrIn));
//if (WSAGetLastError() <> WSAEWOULDBLOCK) and (WSAGetLastError() <> 0) then showmessage(inttostr(WSAGetLastError()));
if len = SOCKET_ERROR then
if Application.MessageBox(
'SOCKET错误,可能是你网线没接好或网络设置有问题,是否中断扫描?',
'SOCKET ERROR',
MB_OKCANCEL + MB_DEFBUTTON1) = IDOK then exit_nbt_thread := true;
{if len <> 50 then
showmessage('Not Send all');}
end;
procedure TNbt.start;
begin
exit_nbt_thread := false;
SendDataThread := TSendDataThread.Create(true);
SendDataThread.FreeOnTerminate := true;
SendDataThread.Resume;
end;
procedure TNbt.Stop;
begin
exit_nbt_thread := true;
SendDataThread.Terminate;
end;
procedure TNbt.Pause;
begin
SendDataThread.Suspend;
end;
procedure TNbt.Restart;
begin
SendDataThread.Resume;
end;
end.