超难网络问题,有人能解决吗?

时间:2021-04-19 21:55:01
当一台电脑接上网线进入局域网中,服务器立即能知道接上来的电脑的IP,怎么实现?

条件,服务器并不知道何时会有电脑接入,被接入的电脑没有安装任何客户端,只有WindowsXP

23 个解决方案

#1


不能用 每隔一段时间ping一次网络内所有电脑,因为这样消耗太大,而且有些电脑是禁止了ping的

#2


如果客户端不装任何东西的话,挺难
本来服务器遍历网络内所有机器(网上邻居)应该可以实现,不过如果你要实时知道的话,就很难了,总不能服务器不干别的,就不停的遍历吧

#3


楼主的要求太高,俗话说鱼和熊掌不能兼得,

#4


真的超难

#5



看你的网络结构了,如果服务器也是路由器,或者代理,那么去读取服务器的ARP Table即可.
http://community.csdn.net/Expert/topic/4722/4722321.xml?temp=.3433191;

如果服务器不是路由和代理,那么就嗅探ARP包了.

如果网络是交换式的,只有循环发送ARP包或者ping,或者TCP ping.

#6


啥子超难哦。结构很简单,线程+网络扫描。 只是实现的代码比较长而已。

#7


unit LanScan;

interface

uses
  Windows, Messages, SysUtils, Forms, Classes, WinSock;

const
  NBTPort = 137;                                    //设定对端UDP端口号
  UDPPort = 8327;                                   //设定本端UDP端口号
  WM_SOCK = WM_USER + $0001;                        //自定义windows消息
  Over_IP = 'Over';                                 //组件退出时的标志

  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);

type
  TNbt = class;

  TSendThread = class(TThread)
  private
   { Private declarations }
   FNbt        : TNbt;
   FIP         : string;                              //当前探测的IP地址
   FEvent      : THandle;                             //延迟事件句柄
  protected
   { protected declarations }
   procedure SendData;                                //发送数据
   procedure NilThread;                               //设置线程结束标识
   procedure Execute; override;
   procedure SetEvents(const nIP: string);            //取消延迟
  public
   { public declarations }
   ID : integer;                                      //线程实例标识
   constructor Create(AOwner: TNbt);
  end;

  TOnBegin = procedure (const nIPNumber: integer) of object;
  TOnEnd   = procedure (const nTotalScan: integer) of object;
  TOnProcess = procedure (const nHasDone: integer) of object;
  TOnStatus = procedure (const nMsg: string) of object;
  //扫描状态
  TOnReceive = procedure (const nIP, nHostName, nUserName,
                                nGroupName, nMacAddr: string) of object;

  TNBT = class(TComponent)
  private
   { Private declarations }
   FBusy     : boolean;                               //正在扫描
   FEndIP,                                            //结束IP
   FBeginIP  : string;                                //开始IP
   FTimeOut  : integer;                               //超时间隔
   FIPList   : TStrings;                              //开始到结束
   FLock     : TRTLCriticalSection;                   //临界区变量
   FData     : array [0..49] of byte;                 //NbtstatPacket
   FHasDone  : integer;                               //已扫描个数

   FOnStatus : TOnStatus;                             //扫描状态
   FOnReceive: TOnReceive;                            //数据解析
   FOnBegin  : TOnBegin;                              //扫描开始
   FOnEnd    : TOnEnd;                                //扫描结束
   FOnProcess: TOnProcess;                            //扫描过程

   FHandle        : HWnd;                             //消息处理使用
   FSock          : TSocket;                          //套节字
   FAddr          : TSockAddr;
   FSockAddrIn    : TSockAddrIn;

   FThreadNum     : integer;                          //线程个数
   FThreads       : array of TSendThread;             //扫描线程
  protected
   { protected declarations }
   function GetIPList: boolean;
   
   procedure EnterCS;                                 //进入临界区
   procedure LeaveCS;                                 //离开临界区
   procedure SendData(const nIP:string);              //发送数据
   procedure ReadData(var nMessage: TMessage);        //消息处理

   procedure SetEvents(const nIP: string);            //取消延迟
   procedure SetThreadNum(const nNum: integer);
   procedure RecvNbMsg(nBuf: array of byte; nLen: integer; const nIP: string);
  public
   { public declarations }
   constructor Create(AOwner: TComponent); override;  //创建
   destructor Destroy; override;                      //销毁
   procedure StartScan;                               //开始扫描
   procedure StopScan;                                //停止扫描
   procedure FreeThreads;                             //释放线程
   procedure NilThread(const nID: integer);           //设置线程结束标识
  published
   { published declarations }
   property EndIP   : string read FEndIP write FEndIP;
   property BeginIP : string read FBeginIP write FBeginIP;
   property TimeOut : integer read FTimeOut write FTimeOut;
   property ThreadNum: integer read FThreadNum write SetThreadNum;
   property OnStatus: TOnStatus read FOnStatus write FOnStatus;
   property OnReceive: TOnReceive read FOnReceive write FOnReceive;
   property OnEnd   : TOnEnd   read FOnEnd write FOnEnd;
   property OnBegin : TOnBegin read FOnBegin write FOnBegin;
   property OnProcess: TOnProcess read FOnProcess write FOnProcess;
  end;
procedure Register;

implementation

procedure Register;
begin
  RegisterComponents('MyUse', [TNBT]);
end;

//Name: IsLegalIP
//Param: nIP,待测试IP
//Return: 若nIP合法返回真
function IsLegalIP(const nIP: string): boolean;
begin                                  
  if inet_addr(pchar(nIP))=INADDR_NONE then
       Result := false
  else Result := True;
end;

#8


{************************ TSendThread ************************}
constructor TSendThread.Create(AOwner: TNbt);
begin
   inherited Create(True);
   FNbt := AOwner;
   FreeOnTerminate := True;
   FEvent := CreateEvent(nil, True, False, nil);
end;

procedure TSendThread.SendData;
begin
  FNbt.SendData(FIP);
end;

procedure TSendThread.NilThread;
begin
  FNbt.NilThread(ID);
end;

procedure TSendThread.SetEvents(const nIP: string);
begin
  if (nIP=FIP) or (nIP=Over_IP) then SetEvent(FEvent);
end;

procedure TSendThread.Execute;
begin
  while not Terminated do
  begin
     FIP := '';   FNbt.EnterCS;
     if FNbt.FIPList.Count = 0 then
     begin
        FNbt.LeaveCS;
        Break;
     end;

     FIP := FNbt.FIPList[0];
     FNbt.FIPList.Delete(0);
     FNbt.LeaveCS;

     Synchronize(SendData);
     WaitForSingleObject(FEvent, FNbt.FTimeOut);
     ResetEvent(FEvent);
  end;

  CloseHandle(FEvent);
  Synchronize(NilThread);
end;

{************************* TNBT ***************************}
constructor TNBT.Create(AOwner: TComponent);
begin
   inherited Create(AOwner);
   FTimeOut  := 100;
   FBusy     := False;
   FEndIP    := '127.0.0.1';
   FBeginIP  := '127.0.0.1';
   FThreadNum:= 3;
end;

destructor TNBT.Destroy;
begin
  StopScan;
  inherited Destroy;
end;

procedure TNBT.EnterCS;
begin
  EnterCriticalSection(FLock);
end;

procedure TNBT.LeaveCS;
begin
  LeaveCriticalSection(FLock);
end;

procedure TNBT.SetThreadNum(const nNum: integer);
begin
  if (nNum > 5) or (nNum < 1) then
     raise Exception.Create('线程个数最好在1-5之间');
  FThreadNum := nNum;
end;

procedure TNBT.NilThread(const nID: integer);
var i: integer;
begin
  for i:= Low(FThreads) to High(FThreads) do
   if Assigned(FThreads[i]) and (FThreads[i].ID = nID) then
   begin
      FThreads[i] := nil;
      Break;
   end;
   
  for i:= Low(FThreads) to High(FThreads) do
    if Assigned(FThreads[i]) then Exit; 
  StopScan;
end;

procedure TNBT.FreeThreads;
var i: integer;
begin
  for i:= Low(FThreads) to High(FThreads) do
  begin
     if not Assigned(FThreads[i]) then Continue;
     FThreads[i].Terminate;
     FThreads[i].SetEvents(Over_IP);
  end;
  SetLength(FThreads,0);
end;

procedure TNBT.StartScan;
var i : integer;
    nWSAData: TWSAData;
begin
   if FBusy then exit;
   FHasDone := 0;
   FIPList := TStringList.Create;
   if not GetIPList then
   begin
      FIPList.Free;
      Exit;
   end;

   FHandle := AllocateHWnd(ReadData);
   InitializeCriticalSection(FLock);
   if WSAStartup($101, nWSAData)=1 then
      Exception.Create('WinSock初始化失败');

   FSock := Socket(AF_INET, SOCK_DGRAM, 0);
   if (FSock = INVALID_SOCKET) then
   begin
      CloseSocket(FSock);
      Exception.Create('Socket创建失败');
   end;

   FAddr.sin_family := AF_INET;
   FAddr.sin_addr.S_addr := INADDR_ANY;
   FAddr.sin_port := htons(UDPPORT);
   if Bind(FSock, FAddr, sizeof(FAddr)) <> 0  then
   begin
      CloseSocket(FSock);
      Exception.Create('WinSock绑定失败');
   end;
   WSAAsyncSelect(FSock, FHandle, WM_SOCK, FD_READ);

   FillChar(FSockAddrIn, SizeOf(FSockAddrIn), #0);
   FSockAddrIn.SIn_Family := AF_INET;
   FSockAddrIn.SIn_Port := htons(NBTPORT);
   for i:=0 to 49 do FData[i] := NbtstatPacket[i];

   SetLength(FThreads, FThreadNum);
   for i:=Low(FThreads) to High(FThreads) do
   begin
      FThreads[i] := TSendThread.Create(self);
      FThreads[i].ID := i;
      Fthreads[i].Resume;
   end;

   FBusy := True;
   if Assigned(FOnBegin) then FOnBegin(FIPList.Count);
end;

procedure TNBT.StopScan;
begin
  if FBusy then
  begin
     FreeThreads;   
     FIPList.Free;
     WSACleanup();
     DeallocateHWnd(FHandle);
     DeleteCriticalSection(FLock);
     FBusy := False;
  end;
  if not (csDestroying in ComponentState)
     and Assigned(FOnEnd) then FOnEnd(FHasDone);
end;

function TNBT.GetIPList: boolean;
var i: integer;
    nIP: string;
    nIP1,nIP2: dWord;
begin
  Result := False;
  if not (IsLegalIP(FEndIP) and IsLegalIP(FBeginIP)) then exit;

  nIP1 := ntohl(inet_addr(pchar(FBeginIP)));
  nIP2 := ntohl(inet_addr(pchar(FEndIP)));
  for i := nIP1 to nIP2 do
  begin
    //去掉x.x.x.0或x.x.x.255的地址。
    if (((i - 255) mod 256)=0)or((i mod 256)=0) then continue;
    nIP := inet_ntoa(in_addr(htonl(i)));
    FIPList.Add(nIP);
  end;
  Result := True;
end;

procedure TNBT.ReadData(var nMessage: TMessage);
var nIP:string;
    nEvent: word;
    nLen1,nLen2: integer;
    nBuf: array [1..500] of byte;
begin
   if nMessage.msg <> WM_SOCK then exit;
   nLen1 := SizeOf(FSockAddrIn);
   nEvent := WSAGetSelectEvent(nMessage.LParam);

   if nEvent = FD_READ then
   begin
      nLen2 := recvfrom(FSock, nBuf, sizeof(nBuf), 0, FSockAddrIn, nLen1);
      if nLen2 > 0 then
      begin
        with FSockAddrIn.sin_addr.S_un_b do
          nIP:=format('%d.%d.%d.%d',[ord(s_b1),ord(s_b2),ord(s_b3),ord(s_b4)]);

        RecvNbMsg(nBuf, nLen2, nIP);
      end;
      SetEvents(nIP);
   end;
end;

procedure TNBT.RecvNbMsg(nBuf: array of byte; nLen: integer; const nIP: string);
var i,j,nPos,nCount: integer;
    sStr,
    nHostName, nUserName,
    nGroupName, nMacAddr: string;
begin
   nCount := 0;
   for i:=1 to nlen do
   begin
      if((nBuf[i]=$21) and (nBuf[i+1]=$00) and (nBuf[i+2]=$01)) then
      begin
        nCount := nBuf[i+9];
        break;
      end;
   end;

   if nCount = 0 then exit;
   sStr := '';
   nPos := i + 10;

   for i := nPos to (nPos + 18*nCount - 1) do
   begin
      if (((i - nPos) mod 18) =0) then
      begin
         for j:=0 to 14 do
         begin
            if Trim(Char(nBuf[i+j])) = '' then nBuf[i+j] := Ord(' ');
            sStr := sStr + Char(nBuf[i+j]);
         end;

         if (nBuf[i+16] and $80)=$80 then
         begin
           if nBuf[i+15]=$0 then nGroupName := Trim(sStr);
         end else
         begin
            if nBuf[i+15]=$3 then nUserName := Trim(sStr)
            else
            if nBuf[i+15]=$20 then nHostName := Trim(sStr); 
         end;

         sStr :='';
      end;
   end;

   for i:=0 to 5 do
       sStr := sStr + Format('%.2x.',[nBuf[i+nPos+18*nCount]]);
   Delete(sStr, Length(sStr), 1);
   nMacAddr := Trim(sStr);

   if Assigned(FOnReceive) then
      FOnReceive(nIP,nHostName,nUserName,nGroupName,nMacAddr);
end;

procedure TNBT.SendData(const nIP: string);
var nLen : integer; 
begin
   FSockAddrIn.SIn_Addr.S_addr := inet_addr(pchar(nIP));
   nLen := SendTo(FSock, FData[0],50, 0, FSockAddrIn, sizeof(FSockAddrIn));

   if Assigned(FOnStatus) then
   begin
      if nLen <> 50 then
         FOnStatus('数据没有发送完毕') else
      if nLen = SOCKET_ERROR then
         FOnStatus('WinSock错误,发送失败')
      else FOnStatus('正在扫描,主机: ' + nIP);
   end;

   Inc(FHasDone);
   if Assigned(FOnProcess) then FOnProcess(FHasDone);
end;

procedure TNBT.SetEvents(const nIP: string);
var i: integer;
begin
  for i:=Low(FThreads) to High(FThreads) do
   if Assigned(FThreads[i]) then FThreads[i].SetEvents(nIP);
end;

end.

#9


新建一个package把这个上边的pas文件添加到里边安装后有一个组件nbt

////
procedure TForm1.cmdStartScanClick(Sender: TObject);
begin
  self.Nbt1.BeginIP:='192.168.168.1';
  self.Nbt1.EndIP:='192.168.168.253';
  self.Nbt1.StartScan;
end;

procedure TForm1.Nbt1Receive(const nIP, nHostName, nUserName, nGroupName,
  nMacAddr: String);
begin
  self.ListBox1.Items.Add( nip+'=='+nMacAddr );
end;

procedure TForm1.cmdStopScanClick(Sender: TObject);
begin
  self.Nbt1.StopScan;
end;

#10


sanmaotuo(老冯) 可能没理解我的意思

按你说的那样确实很简单(如果这样能解决就不叫超难问题了),但是,不停的扫描网络是不现实的。而且要把网内所有电脑都扫描一遍是不现实的。

你想想看就比如这个局域网是192.168.x.x开头的机器,那么要全部扫描一次需要每次扫描65025台电脑,如果每次扫描0.5秒钟作为TimeOut,也就是9个小时才能完成一次扫描。 等你扫描完,天都亮了


我在考虑是否有局域网专用的方法

化杯粪喂力量  的ARP方法有创意,我先去试验一下,然后告诉大家结果

#11


谢谢  失踪的月亮,我试试看扫描速度

#12


邻居发现机制把,。
由他附近的邻居举报,这是以太网的原理

#13


邻居发现机制是怎么做的? 怎么编写代码?能否给点提示

#14


由于intranet有个特点,广播机制
当一个网卡启用,或者一个pc查找另外一台需要的机器,就要发arp包广播,这个广播在网卡底层是任何pc机器都可以接受到的,只是在应用层如果不需要的话将把它抛弃

简单说

一台机器接入网络时,将发送一个arp广播,告诉所有的人,我来了。这也是如果同一个网络设置到两个相同的 ip地址系统马上就要报冲突的原因哈


程序实现 要用到ndis编程,接受所有的arp包,解包,就ok了

#15


是个,楼上的说得对啊。

我一个题目就想到了广播,怎么会被认为是超级难题。

#16


说是容易,有没有代码参考一下?

#17


如何实现基于web的指定数据提取?急~~~~~~~~请各位高手指教!

#18


有没有代码参考一下?

#19


采用域管理,就可以实现你的要求。

#20


看来实现还是有难度

#21


原理就如上面说的一样

编程有很多方法实现
可以自己写 tdi 驱动,或者利用winpcap (windows环境下)提供的api ,这样就可以抓取arp包了

自己去查 下winpcap 编程代码,网上很多,就不重复叙述了


#22


偶学习啦.
"一台机器接入网络时,将发送一个arp广播,底层的问题."

#23


以上回答都不是我想要的。勉强结贴。

#1


不能用 每隔一段时间ping一次网络内所有电脑,因为这样消耗太大,而且有些电脑是禁止了ping的

#2


如果客户端不装任何东西的话,挺难
本来服务器遍历网络内所有机器(网上邻居)应该可以实现,不过如果你要实时知道的话,就很难了,总不能服务器不干别的,就不停的遍历吧

#3


楼主的要求太高,俗话说鱼和熊掌不能兼得,

#4


真的超难

#5



看你的网络结构了,如果服务器也是路由器,或者代理,那么去读取服务器的ARP Table即可.
http://community.csdn.net/Expert/topic/4722/4722321.xml?temp=.3433191;

如果服务器不是路由和代理,那么就嗅探ARP包了.

如果网络是交换式的,只有循环发送ARP包或者ping,或者TCP ping.

#6


啥子超难哦。结构很简单,线程+网络扫描。 只是实现的代码比较长而已。

#7


unit LanScan;

interface

uses
  Windows, Messages, SysUtils, Forms, Classes, WinSock;

const
  NBTPort = 137;                                    //设定对端UDP端口号
  UDPPort = 8327;                                   //设定本端UDP端口号
  WM_SOCK = WM_USER + $0001;                        //自定义windows消息
  Over_IP = 'Over';                                 //组件退出时的标志

  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);

type
  TNbt = class;

  TSendThread = class(TThread)
  private
   { Private declarations }
   FNbt        : TNbt;
   FIP         : string;                              //当前探测的IP地址
   FEvent      : THandle;                             //延迟事件句柄
  protected
   { protected declarations }
   procedure SendData;                                //发送数据
   procedure NilThread;                               //设置线程结束标识
   procedure Execute; override;
   procedure SetEvents(const nIP: string);            //取消延迟
  public
   { public declarations }
   ID : integer;                                      //线程实例标识
   constructor Create(AOwner: TNbt);
  end;

  TOnBegin = procedure (const nIPNumber: integer) of object;
  TOnEnd   = procedure (const nTotalScan: integer) of object;
  TOnProcess = procedure (const nHasDone: integer) of object;
  TOnStatus = procedure (const nMsg: string) of object;
  //扫描状态
  TOnReceive = procedure (const nIP, nHostName, nUserName,
                                nGroupName, nMacAddr: string) of object;

  TNBT = class(TComponent)
  private
   { Private declarations }
   FBusy     : boolean;                               //正在扫描
   FEndIP,                                            //结束IP
   FBeginIP  : string;                                //开始IP
   FTimeOut  : integer;                               //超时间隔
   FIPList   : TStrings;                              //开始到结束
   FLock     : TRTLCriticalSection;                   //临界区变量
   FData     : array [0..49] of byte;                 //NbtstatPacket
   FHasDone  : integer;                               //已扫描个数

   FOnStatus : TOnStatus;                             //扫描状态
   FOnReceive: TOnReceive;                            //数据解析
   FOnBegin  : TOnBegin;                              //扫描开始
   FOnEnd    : TOnEnd;                                //扫描结束
   FOnProcess: TOnProcess;                            //扫描过程

   FHandle        : HWnd;                             //消息处理使用
   FSock          : TSocket;                          //套节字
   FAddr          : TSockAddr;
   FSockAddrIn    : TSockAddrIn;

   FThreadNum     : integer;                          //线程个数
   FThreads       : array of TSendThread;             //扫描线程
  protected
   { protected declarations }
   function GetIPList: boolean;
   
   procedure EnterCS;                                 //进入临界区
   procedure LeaveCS;                                 //离开临界区
   procedure SendData(const nIP:string);              //发送数据
   procedure ReadData(var nMessage: TMessage);        //消息处理

   procedure SetEvents(const nIP: string);            //取消延迟
   procedure SetThreadNum(const nNum: integer);
   procedure RecvNbMsg(nBuf: array of byte; nLen: integer; const nIP: string);
  public
   { public declarations }
   constructor Create(AOwner: TComponent); override;  //创建
   destructor Destroy; override;                      //销毁
   procedure StartScan;                               //开始扫描
   procedure StopScan;                                //停止扫描
   procedure FreeThreads;                             //释放线程
   procedure NilThread(const nID: integer);           //设置线程结束标识
  published
   { published declarations }
   property EndIP   : string read FEndIP write FEndIP;
   property BeginIP : string read FBeginIP write FBeginIP;
   property TimeOut : integer read FTimeOut write FTimeOut;
   property ThreadNum: integer read FThreadNum write SetThreadNum;
   property OnStatus: TOnStatus read FOnStatus write FOnStatus;
   property OnReceive: TOnReceive read FOnReceive write FOnReceive;
   property OnEnd   : TOnEnd   read FOnEnd write FOnEnd;
   property OnBegin : TOnBegin read FOnBegin write FOnBegin;
   property OnProcess: TOnProcess read FOnProcess write FOnProcess;
  end;
procedure Register;

implementation

procedure Register;
begin
  RegisterComponents('MyUse', [TNBT]);
end;

//Name: IsLegalIP
//Param: nIP,待测试IP
//Return: 若nIP合法返回真
function IsLegalIP(const nIP: string): boolean;
begin                                  
  if inet_addr(pchar(nIP))=INADDR_NONE then
       Result := false
  else Result := True;
end;

#8


{************************ TSendThread ************************}
constructor TSendThread.Create(AOwner: TNbt);
begin
   inherited Create(True);
   FNbt := AOwner;
   FreeOnTerminate := True;
   FEvent := CreateEvent(nil, True, False, nil);
end;

procedure TSendThread.SendData;
begin
  FNbt.SendData(FIP);
end;

procedure TSendThread.NilThread;
begin
  FNbt.NilThread(ID);
end;

procedure TSendThread.SetEvents(const nIP: string);
begin
  if (nIP=FIP) or (nIP=Over_IP) then SetEvent(FEvent);
end;

procedure TSendThread.Execute;
begin
  while not Terminated do
  begin
     FIP := '';   FNbt.EnterCS;
     if FNbt.FIPList.Count = 0 then
     begin
        FNbt.LeaveCS;
        Break;
     end;

     FIP := FNbt.FIPList[0];
     FNbt.FIPList.Delete(0);
     FNbt.LeaveCS;

     Synchronize(SendData);
     WaitForSingleObject(FEvent, FNbt.FTimeOut);
     ResetEvent(FEvent);
  end;

  CloseHandle(FEvent);
  Synchronize(NilThread);
end;

{************************* TNBT ***************************}
constructor TNBT.Create(AOwner: TComponent);
begin
   inherited Create(AOwner);
   FTimeOut  := 100;
   FBusy     := False;
   FEndIP    := '127.0.0.1';
   FBeginIP  := '127.0.0.1';
   FThreadNum:= 3;
end;

destructor TNBT.Destroy;
begin
  StopScan;
  inherited Destroy;
end;

procedure TNBT.EnterCS;
begin
  EnterCriticalSection(FLock);
end;

procedure TNBT.LeaveCS;
begin
  LeaveCriticalSection(FLock);
end;

procedure TNBT.SetThreadNum(const nNum: integer);
begin
  if (nNum > 5) or (nNum < 1) then
     raise Exception.Create('线程个数最好在1-5之间');
  FThreadNum := nNum;
end;

procedure TNBT.NilThread(const nID: integer);
var i: integer;
begin
  for i:= Low(FThreads) to High(FThreads) do
   if Assigned(FThreads[i]) and (FThreads[i].ID = nID) then
   begin
      FThreads[i] := nil;
      Break;
   end;
   
  for i:= Low(FThreads) to High(FThreads) do
    if Assigned(FThreads[i]) then Exit; 
  StopScan;
end;

procedure TNBT.FreeThreads;
var i: integer;
begin
  for i:= Low(FThreads) to High(FThreads) do
  begin
     if not Assigned(FThreads[i]) then Continue;
     FThreads[i].Terminate;
     FThreads[i].SetEvents(Over_IP);
  end;
  SetLength(FThreads,0);
end;

procedure TNBT.StartScan;
var i : integer;
    nWSAData: TWSAData;
begin
   if FBusy then exit;
   FHasDone := 0;
   FIPList := TStringList.Create;
   if not GetIPList then
   begin
      FIPList.Free;
      Exit;
   end;

   FHandle := AllocateHWnd(ReadData);
   InitializeCriticalSection(FLock);
   if WSAStartup($101, nWSAData)=1 then
      Exception.Create('WinSock初始化失败');

   FSock := Socket(AF_INET, SOCK_DGRAM, 0);
   if (FSock = INVALID_SOCKET) then
   begin
      CloseSocket(FSock);
      Exception.Create('Socket创建失败');
   end;

   FAddr.sin_family := AF_INET;
   FAddr.sin_addr.S_addr := INADDR_ANY;
   FAddr.sin_port := htons(UDPPORT);
   if Bind(FSock, FAddr, sizeof(FAddr)) <> 0  then
   begin
      CloseSocket(FSock);
      Exception.Create('WinSock绑定失败');
   end;
   WSAAsyncSelect(FSock, FHandle, WM_SOCK, FD_READ);

   FillChar(FSockAddrIn, SizeOf(FSockAddrIn), #0);
   FSockAddrIn.SIn_Family := AF_INET;
   FSockAddrIn.SIn_Port := htons(NBTPORT);
   for i:=0 to 49 do FData[i] := NbtstatPacket[i];

   SetLength(FThreads, FThreadNum);
   for i:=Low(FThreads) to High(FThreads) do
   begin
      FThreads[i] := TSendThread.Create(self);
      FThreads[i].ID := i;
      Fthreads[i].Resume;
   end;

   FBusy := True;
   if Assigned(FOnBegin) then FOnBegin(FIPList.Count);
end;

procedure TNBT.StopScan;
begin
  if FBusy then
  begin
     FreeThreads;   
     FIPList.Free;
     WSACleanup();
     DeallocateHWnd(FHandle);
     DeleteCriticalSection(FLock);
     FBusy := False;
  end;
  if not (csDestroying in ComponentState)
     and Assigned(FOnEnd) then FOnEnd(FHasDone);
end;

function TNBT.GetIPList: boolean;
var i: integer;
    nIP: string;
    nIP1,nIP2: dWord;
begin
  Result := False;
  if not (IsLegalIP(FEndIP) and IsLegalIP(FBeginIP)) then exit;

  nIP1 := ntohl(inet_addr(pchar(FBeginIP)));
  nIP2 := ntohl(inet_addr(pchar(FEndIP)));
  for i := nIP1 to nIP2 do
  begin
    //去掉x.x.x.0或x.x.x.255的地址。
    if (((i - 255) mod 256)=0)or((i mod 256)=0) then continue;
    nIP := inet_ntoa(in_addr(htonl(i)));
    FIPList.Add(nIP);
  end;
  Result := True;
end;

procedure TNBT.ReadData(var nMessage: TMessage);
var nIP:string;
    nEvent: word;
    nLen1,nLen2: integer;
    nBuf: array [1..500] of byte;
begin
   if nMessage.msg <> WM_SOCK then exit;
   nLen1 := SizeOf(FSockAddrIn);
   nEvent := WSAGetSelectEvent(nMessage.LParam);

   if nEvent = FD_READ then
   begin
      nLen2 := recvfrom(FSock, nBuf, sizeof(nBuf), 0, FSockAddrIn, nLen1);
      if nLen2 > 0 then
      begin
        with FSockAddrIn.sin_addr.S_un_b do
          nIP:=format('%d.%d.%d.%d',[ord(s_b1),ord(s_b2),ord(s_b3),ord(s_b4)]);

        RecvNbMsg(nBuf, nLen2, nIP);
      end;
      SetEvents(nIP);
   end;
end;

procedure TNBT.RecvNbMsg(nBuf: array of byte; nLen: integer; const nIP: string);
var i,j,nPos,nCount: integer;
    sStr,
    nHostName, nUserName,
    nGroupName, nMacAddr: string;
begin
   nCount := 0;
   for i:=1 to nlen do
   begin
      if((nBuf[i]=$21) and (nBuf[i+1]=$00) and (nBuf[i+2]=$01)) then
      begin
        nCount := nBuf[i+9];
        break;
      end;
   end;

   if nCount = 0 then exit;
   sStr := '';
   nPos := i + 10;

   for i := nPos to (nPos + 18*nCount - 1) do
   begin
      if (((i - nPos) mod 18) =0) then
      begin
         for j:=0 to 14 do
         begin
            if Trim(Char(nBuf[i+j])) = '' then nBuf[i+j] := Ord(' ');
            sStr := sStr + Char(nBuf[i+j]);
         end;

         if (nBuf[i+16] and $80)=$80 then
         begin
           if nBuf[i+15]=$0 then nGroupName := Trim(sStr);
         end else
         begin
            if nBuf[i+15]=$3 then nUserName := Trim(sStr)
            else
            if nBuf[i+15]=$20 then nHostName := Trim(sStr); 
         end;

         sStr :='';
      end;
   end;

   for i:=0 to 5 do
       sStr := sStr + Format('%.2x.',[nBuf[i+nPos+18*nCount]]);
   Delete(sStr, Length(sStr), 1);
   nMacAddr := Trim(sStr);

   if Assigned(FOnReceive) then
      FOnReceive(nIP,nHostName,nUserName,nGroupName,nMacAddr);
end;

procedure TNBT.SendData(const nIP: string);
var nLen : integer; 
begin
   FSockAddrIn.SIn_Addr.S_addr := inet_addr(pchar(nIP));
   nLen := SendTo(FSock, FData[0],50, 0, FSockAddrIn, sizeof(FSockAddrIn));

   if Assigned(FOnStatus) then
   begin
      if nLen <> 50 then
         FOnStatus('数据没有发送完毕') else
      if nLen = SOCKET_ERROR then
         FOnStatus('WinSock错误,发送失败')
      else FOnStatus('正在扫描,主机: ' + nIP);
   end;

   Inc(FHasDone);
   if Assigned(FOnProcess) then FOnProcess(FHasDone);
end;

procedure TNBT.SetEvents(const nIP: string);
var i: integer;
begin
  for i:=Low(FThreads) to High(FThreads) do
   if Assigned(FThreads[i]) then FThreads[i].SetEvents(nIP);
end;

end.

#9


新建一个package把这个上边的pas文件添加到里边安装后有一个组件nbt

////
procedure TForm1.cmdStartScanClick(Sender: TObject);
begin
  self.Nbt1.BeginIP:='192.168.168.1';
  self.Nbt1.EndIP:='192.168.168.253';
  self.Nbt1.StartScan;
end;

procedure TForm1.Nbt1Receive(const nIP, nHostName, nUserName, nGroupName,
  nMacAddr: String);
begin
  self.ListBox1.Items.Add( nip+'=='+nMacAddr );
end;

procedure TForm1.cmdStopScanClick(Sender: TObject);
begin
  self.Nbt1.StopScan;
end;

#10


sanmaotuo(老冯) 可能没理解我的意思

按你说的那样确实很简单(如果这样能解决就不叫超难问题了),但是,不停的扫描网络是不现实的。而且要把网内所有电脑都扫描一遍是不现实的。

你想想看就比如这个局域网是192.168.x.x开头的机器,那么要全部扫描一次需要每次扫描65025台电脑,如果每次扫描0.5秒钟作为TimeOut,也就是9个小时才能完成一次扫描。 等你扫描完,天都亮了


我在考虑是否有局域网专用的方法

化杯粪喂力量  的ARP方法有创意,我先去试验一下,然后告诉大家结果

#11


谢谢  失踪的月亮,我试试看扫描速度

#12


邻居发现机制把,。
由他附近的邻居举报,这是以太网的原理

#13


邻居发现机制是怎么做的? 怎么编写代码?能否给点提示

#14


由于intranet有个特点,广播机制
当一个网卡启用,或者一个pc查找另外一台需要的机器,就要发arp包广播,这个广播在网卡底层是任何pc机器都可以接受到的,只是在应用层如果不需要的话将把它抛弃

简单说

一台机器接入网络时,将发送一个arp广播,告诉所有的人,我来了。这也是如果同一个网络设置到两个相同的 ip地址系统马上就要报冲突的原因哈


程序实现 要用到ndis编程,接受所有的arp包,解包,就ok了

#15


是个,楼上的说得对啊。

我一个题目就想到了广播,怎么会被认为是超级难题。

#16


说是容易,有没有代码参考一下?

#17


如何实现基于web的指定数据提取?急~~~~~~~~请各位高手指教!

#18


有没有代码参考一下?

#19


采用域管理,就可以实现你的要求。

#20


看来实现还是有难度

#21


原理就如上面说的一样

编程有很多方法实现
可以自己写 tdi 驱动,或者利用winpcap (windows环境下)提供的api ,这样就可以抓取arp包了

自己去查 下winpcap 编程代码,网上很多,就不重复叙述了


#22


偶学习啦.
"一台机器接入网络时,将发送一个arp广播,底层的问题."

#23


以上回答都不是我想要的。勉强结贴。