Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1257521
  • 博文数量: 788
  • 博客积分: 4000
  • 博客等级: 上校
  • 技术积分: 7005
  • 用 户 组: 普通用户
  • 注册时间: 2008-08-19 15:52
文章存档

2017年(81)

2011年(1)

2009年(369)

2008年(337)

分类:

2008-08-19 15:55:42



当一台电脑接上网线进入局域网中,服务器立即能知道接上来的电脑的IP,怎么实现?  
   
  条件,服务器并不知道何时会有电脑接入,被接入的电脑没有安装任何客户端,只有WindowsXP

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

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

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

真的超难

 
  看你的网络结构了,如果服务器也是路由器,或者代理,那么去读取服务器的ARP Table即可.  
   
   
  如果服务器不是路由和代理,那么就嗅探ARP包了.  
   
  如果网络是交换式的,只有循环发送ARP包或者ping,或者TCP   ping.  
   
 

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

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;

{************************   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.

新建一个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;

sanmaotuo(老冯)   可能没理解我的意思  
   
  按你说的那样确实很简单(如果这样能解决就不叫超难问题了),但是,不停的扫描网络是不现实的。而且要把网内所有电脑都扫描一遍是不现实的。  
   
  你想想看就比如这个局域网是192.168.x.x开头的机器,那么要全部扫描一次需要每次扫描65025台电脑,如果每次扫描0.5秒钟作为TimeOut,也就是9个小时才能完成一次扫描。   等你扫描完,天都亮了  
   
   
  我在考虑是否有局域网专用的方法  
   
  化杯粪喂力量     的ARP方法有创意,我先去试验一下,然后告诉大家结果

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

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

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

由于intranet有个特点,广播机制  
  当一个网卡启用,或者一个pc查找另外一台需要的机器,就要发arp包广播,这个广播在网卡底层是任何pc机器都可以接受到的,只是在应用层如果不需要的话将把它抛弃  
   
  简单说  
   
  一台机器接入网络时,将发送一个arp广播,告诉所有的人,我来了。这也是如果同一个网络设置到两个相同的   ip地址系统马上就要报冲突的原因哈  
   
   
  程序实现   要用到ndis编程,接受所有的arp包,解包,就ok了  
 

是个,楼上的说得对啊。  
   
  我一个题目就想到了广播,怎么会被认为是超级难题。

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

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

有没有代码参考一下?

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

看来实现还是有难度

原理就如上面说的一样  
   
  编程有很多方法实现  
  可以自己写   tdi   驱动,或者利用winpcap   (windows环境下)提供的api   ,这样就可以抓取arp包了  
   
  自己去查   下winpcap   编程代码,网上很多,就不重复叙述了  
   
   
 

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

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

阅读(394) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~