当局域网断开时,操作系统任务栏会有一个网络断开的图标出现,如何编程实现对局域网是否连通的判断呢?

解决方案 »

  1.   

    http://expert.csdn.net/Expert/topic/1855/1855796.xml?temp=.3466608
      

  2.   

    基于ICMP的PING,和基于SOCKET的通讯程序都可以用来检测
      

  3.   

    以上方法均不适用,我的程序将在以下环境中使用:
    1.局域网中没有网关和域,不能连上Internet
    2.所有计算机都没有自己指定IP,也没有计算机专门提供分配IP的服务
    3.所有计算机都拒绝 ping
    3.要求在计算机启动后,没有访问任何网络资源,也没有其他计算机来访问的前提下(操作系统自己访问网络,不受该限制)判断局域网是否连通.请问高手,该如何实现?
      

  4.   

    对于3:可以把程序写成服务,设置为自动启动!//检查Internet 的连接性
    BOOL  CheckOffline()
    {
        DWORD ConnectState;
        DWORD StateSize;
        StateSize=sizeof(ConnectState);
        BOOL result=false;
        //检查当前的Internet设置是否可用 
        if(InternetQueryOption(NULL,INTERNET_OPTION_CONNECTED_STATE,&ConnectState,StateSize)
        {
           if(ConnectState & INTERNET_STATE_DISCONNECTED != 2)
           {    
           //检查连接到internet了吗?
           if InternetheckConnection('http://www.sohu,com/'1,0)
              GetDlgItem(IDC_EDIT1)->SetDlgItemText(IDC_EDIT1,_T("Connected"));
           else 'DisConnected'
           result = true;
           }
        }
    return result;
    }
      

  5.   

    用原始套接字实现,发送SYN请求,接收到ACK就表示连通,而且很快速、很隐蔽。
      

  6.   

    上面那个有点错误!//检查Internet 的连接性
    BOOL  CMyGoodsDlg::CheckOnline()
    {
        DWORD ConnectState;
        DWORD StateSize;
        StateSize=sizeof(ConnectState);
        BOOL result=false;
        //检查当前的Internet设置是否可用 
        if(InternetQueryOption(NULL,INTERNET_OPTION_CONNECTED_STATE,&ConnectState,&StateSize))
        {
    if((ConnectState & INTERNET_STATE_DISCONNECTED) != 2)
    {    
    //检查连接到internet了吗?
    if (InternetCheckConnection("http://www.sohu.com/",1,0))
    {
    GetDlgItem(IDC_TESTALT)->SetDlgItemText(IDC_TESTALT,_T("Connected"));
    result = true;
    }
    else GetDlgItem(IDC_TESTALT)->SetDlgItemText(IDC_TESTALT,_T("DisConnected"));
    }
        }
    return result;
    }
    //是否上网   //INTERNET_CONNECTED_INFO
    void CMyGoodsDlg::OnIsonline() 
    {    CheckOnline();
           return ;    DWORD flags;     //上网方式
        InternetGetConnectedState(&flags,0);

        if( (flags & INTERNET_CONNECTION_MODEM) || (flags & INTERNET_CONNECTION_LAN)  ||(flags & INTERNET_CONNECTION_PROXY))   {
    TCHAR bufferpath[_MAX_PATH];
    PTCHAR pBuf;
    pBuf=bufferpath;
    GetSystemDirectory(pBuf,_MAX_PATH);
    PTCHAR pPos=_tcsstr(pBuf,_T("System32"));
    VERIFY((pPos-pBuf-1)>0);
    bufferpath[pPos-pBuf-1]='\0';
    _tcscat(pBuf,"\\Media\\Windows 登录音.wav"); 
    //StrTrim(pBuf,_T("system32"));      //这个需要:Shlwapi.h
    CString cs=_T( "已上网");
    //GetDlgItem(IDC_ISONLINE)->
    SetDlgItemText(IDC_ISONLINE, cs);
    sndPlaySound(pBuf,SND_SYNC);
    }
    else GetDlgItem(IDC_TESTALT)->SetWindowText(_T("未上网"));
    }
    //下面这段是MSDN的如何设置代理服务器信息
    The following sample demonstrates how to set proxy information for a LAN connection.BOOL SetConnectionOptions()
    {
        INTERNET_PER_CONN_OPTION_LIST list;
        BOOL    bReturn;
        DWORD   dwBufSize = sizeof(list);    // Fill out list struct.
        list.dwSize = sizeof(list);    // NULL == LAN, otherwise connectoid name.
        list.pszConnection = NULL;    // Set three options.
        list.dwOptionCount = 3;
        list.pOptions = new INTERNET_PER_CONN_OPTION[3];    // Make sure the memory was allocated.
        if(NULL == list.pOptions)
        {
            // Return FALSE if the memory wasn't allocated.
            return FALSE;
        }    // Set flags.
        list.pOptions[0].dwOption = INTERNET_PER_CONN_FLAGS;
        list.pOptions[0].Value.dwValue = PROXY_TYPE_DIRECT |
            PROXY_TYPE_PROXY;    // Set proxy name.
        list.pOptions[1].dwOption = INTERNET_PER_CONN_PROXY_SERVER;
        list.pOptions[1].Value.pszValue = "http://proxy:80";    // Set proxy override.
        list.pOptions[2].dwOption = INTERNET_PER_CONN_PROXY_BYPASS;
        list.pOptions[2].Value.pszValue = "local";    // Set the options on the connection.
        bReturn = InternetSetOption(NULL,
            INTERNET_OPTION_PER_CONNECTION_OPTION, &list, dwBufSize);    // Free the allocated memory.
        delete [] list.pOptions;    return bReturn;
    }
      

  7.   

    Ping就可以,开一个线程做Ping,下面是封装好的发送数据包的Ping类
    // UDPPing.h: interface for the CUDPPing class.
    //
    //////////////////////////////////////////////////////////////////////#if !defined(AFX_UDPPING_H__A28CF5A0_3845_406C_830B_C8E583080AF5__INCLUDED_)
    #define AFX_UDPPING_H__A28CF5A0_3845_406C_830B_C8E583080AF5__INCLUDED_#if _MSC_VER > 1000
    #pragma once
    #endif // _MSC_VER > 1000
    //使用的Winsock版本是2.2
    //#include<winsock2.h>
    //对发送协议结构数据格式的定义
    #define REQ_DATASIZE 32
    //#define WM_MSG_STATUS WM_USER + 0x0100
    //#define WM_MSG_PINGSTOP WM_USER + 0x0101
    typedef struct tagIPHDR
    {
    u_char  VIHL; // Version and IHL
    u_char TOS; // Type Of Service
    short TotLen; // Total Length
    short ID; // Identification
    short FlagOff; // Flags and Fragment Offset
    u_char TTL; // Time To Live
    u_char Protocol; // Protocol
    u_short Checksum; // Checksum
    struct in_addr iaSrc; // Internet Address - Source
    struct in_addr iaDst; // Internet Address - Destination
    }IPHDR, *PIPHDR;
    // ICMP Header - RFC 792
    typedef struct tagICMPHDR
    {
    u_char Type; // Type
    u_char Code; // Code
    u_short Checksum; // Checksum
    u_short ID; // Identification
    u_short Seq; // Sequence
    char Data; // Data
    }ICMPHDR, *PICMPHDR;
    #define REQ_DATASIZE 32 // Echo Request Data size
    #define ICMP_ECHOREQ 8// ICMP Echo Request
    typedef struct tagECHOREQUEST
    {
    ICMPHDR icmpHdr;
    DWORD dwTime;
    char cData[REQ_DATASIZE];
    }ECHOREQUEST, *PECHOREQUEST;
    // ICMP Echo Reply
    typedef struct tagECHOREPLY
    {
    IPHDR ipHdr;
    ECHOREQUEST echoRequest;
    char    cFiller[256];
    }ECHOREPLY, *PECHOREPLY;
    #include "BasePing.h"class CUDPPing : public CBasePing  
    {
    public:
    private:
    u_short in_cksum(u_short *addr, int len);
    DWORD RecvEchoReply(SOCKET s, LPSOCKADDR_IN lpsaFrom, u_char *pTTL);
    int SendEchoRequest(SOCKET s, LPSOCKADDR_IN lpstToAddr);
    int WaitForEchoReply(SOCKET s);
    SOCKET   m_rawSocket;
    int m_iRet;
    public:
    virtual void Serialize(CArchive & ar);
    void Close();
    bool Open(); bool Ping(LPCTSTR pStrHostName, DWORD nPingTimeout);
    CUDPPing();
    virtual ~CUDPPing();
    protected:
    DECLARE_SERIAL(CUDPPing);};#endif // !defined(AFX_UDPPING_H__A28CF5A0_3845_406C_830B_C8E583080AF5__INCLUDED_)
      

  8.   

    // UDPPing.cpp: implementation of the CUDPPing class.
    //
    //////////////////////////////////////////////////////////////////////#include "stdafx.h"
    #include "UDPPing.h"#ifdef _DEBUG
    #undef THIS_FILE
    static char THIS_FILE[]=__FILE__;
    #define new DEBUG_NEW
    #endif//////////////////////////////////////////////////////////////////////
    // Construction/Destruction
    //////////////////////////////////////////////////////////////////////
    IMPLEMENT_SERIAL(CUDPPing,CObject,1);
    CUDPPing::CUDPPing()
    { m_type=2;
    }CUDPPing::~CUDPPing()
    {}bool CUDPPing::Ping(LPCTSTR pStrHostName, DWORD nPingTimeout)
    {
      struct    sockaddr_in saDest;
      struct    sockaddr_in saSrc;
      LPHOSTENT lpHost;
      CString str;
     

      DWORD   dwTimeSent,dwElapsed;
      u_char    cTTL;
    long m_laddr;
    //清零 
    m_laddr = inet_addr((CString)pStrHostName);
    if (m_laddr == INADDR_NONE)
    {

    lpHost = gethostbyname((CString)pStrHostName);
      if (lpHost == NULL)
      {
     
    return FALSE;
    }
      saDest.sin_addr.s_addr = *((u_long FAR *) (lpHost->h_addr));
    }
    else
    {
    saDest.sin_addr.s_addr =m_laddr;
    }
      saDest.sin_family = AF_INET;
      saDest.sin_port = 0;
     
          
      //PING

      SendEchoRequest(m_rawSocket, &saDest);
      m_iRet = WaitForEchoReply(m_rawSocket);
      if (!m_iRet)
      {

      return FALSE;
     
      }
      else
      {
      // 刷新回应  dwTimeSent = RecvEchoReply(m_rawSocket, &saSrc, &cTTL); // 计算剩余时间
      dwElapsed = GetTickCount() - dwTimeSent;
     
      }


    return TRUE;
    }int CUDPPing::WaitForEchoReply(SOCKET s)
    { struct timeval Timeout;
    fd_set readfds; readfds.fd_count = 1;
    readfds.fd_array[0] = s;
    Timeout.tv_sec = 1;
        Timeout.tv_usec = 0;
    return(select(1, &readfds, NULL, NULL, &Timeout));
    }int CUDPPing::SendEchoRequest(SOCKET s, LPSOCKADDR_IN lpstToAddr)
    {
    static ECHOREQUEST echoReq;
    static nId = 1;
    static nSeq = 1;
    int nRet; //填充请求
    echoReq.icmpHdr.Type = ICMP_ECHOREQ;
    echoReq.icmpHdr.Code = 0;
    echoReq.icmpHdr.Checksum = 0;
    echoReq.icmpHdr.ID = nId++;
    echoReq.icmpHdr.Seq = nSeq++; // 填充测试用的数据
    for (nRet = 0; nRet < REQ_DATASIZE; nRet++)
    echoReq.cData[nRet] = ' '+nRet; // Save tick count when sent
    echoReq.dwTime = GetTickCount(); // 把数据放入包中并接受检查
    echoReq.icmpHdr.Checksum = in_cksum((u_short *)&echoReq, sizeof(ECHOREQUEST)); //发送请求的显示信息     
    nRet = sendto(s, /* socket */
     (LPSTR)&echoReq, /* 缓冲 */
     sizeof(ECHOREQUEST),
     0, /* 标志 */
     (LPSOCKADDR)lpstToAddr, /* 定义 */
     sizeof(SOCKADDR_IN));   /* 地址长度 */
    return (nRet);
    }DWORD CUDPPing::RecvEchoReply(SOCKET s, LPSOCKADDR_IN lpsaFrom, u_char *pTTL)
    {
    ECHOREPLY echoReply;
    int nRet;
    int nAddrLen = sizeof(struct sockaddr_in); // 刷新请求连接的信息
    nRet = recvfrom(s, // socket
    (LPSTR)&echoReply, // 缓冲
    sizeof(ECHOREPLY), // 缓冲大小
    0, // 标志
    (LPSOCKADDR)lpsaFrom, // 源地址
    &nAddrLen); // 指向地址长度的指针 // 检测返回的信息 // 返回 time sent and IP TTL
    *pTTL = echoReply.ipHdr.TTL; return(echoReply.echoRequest.dwTime);    }u_short CUDPPing::in_cksum(u_short *addr, int len)
    { register int nleft = len;
    register u_short *w = addr;
    register u_short answer;
    register int sum = 0; /*
     *  由于十进制比较简单采用32位
     *  采用可延伸的16位进制。
     *  当需要时从高16位可扩展至低16位.
     */
    while( nleft > 1 )  
    {
    sum += *w++;
    nleft -= 2;
    } /* 如果有必要。提出一字节 */
    if( nleft == 1 ) {
    u_short u = 0; *(u_char *)(&u) = *(u_char *)w ;
    sum += u;
    } /*
     * 从高16位到低16位
     */
    sum = (sum >> 16) + (sum & 0xffff); /* 添加高16位到低16位 */
    sum += (sum >> 16);
    answer = ~sum; /* 截至16位 */
    return (answer);
    }
    bool CUDPPing::Open()
    {
    m_rawSocket = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
    return TRUE;
    }void CUDPPing::Close()
    {
    closesocket(m_rawSocket);
    }void CUDPPing::Serialize(CArchive &ar)
    {
    if (ar.IsStoring())
    {
    ar<<m_iPingTimes<<m_priority ; // TODO: add storing code here
    }
    else
    {
    ar>>m_iPingTimes>>m_priority ; // TODO: add loading code here
    }
    }
      

  9.   

    转自驱动开发网
    发信人: rain (夜猫子大王), 信区: SysInternals
    标 题: Re: 请问实时发现网络down掉的原理?(转载)
    发信站: 武汉白云黄鹤站 (2001年03月31日09:57:05 星期六), 转信实时检测网线被拔掉是需要网卡设备驱动程序支持的,
    如果驱动程序不支持是无法实现的,NDIS4要求设备驱动程序
    最好提供CheckForHangHandler回调函数。2000会每隔2秒钟
    调用此函数。驱动程序在此函数中检查网卡连线状态,
    如果发生了改变,即拔去了网线或接上了网线,
    驱动程序就会调用NdisMIndicateStatus通知所有的上层NDIS协议驱动程序.
    其中: NDIS_STATUS_MEDIA_DISCONNECT 指示网线被拔掉,
    NDIS_STATUS_MEDIA_CONNECT 指示网线被接上
    NDIS_STATUS_LINK_SPEED_CHANGE 指示网卡速度改变,10/100自适应网卡才有。
    网卡一般都有 status register 指示当然的连线状态,
    也有网卡是通过获得 led status 来知道当前的连线状态的,
    即绿灯亮表示连线,灭表示没有。
    有些网卡拔掉或接上网线时会产生中断,在中断处理程序中一般也
    检测网络连线状态并调用NdisMIndicateStatus,这样连线状态
    在2000中就实时反应出来了,否则会在2秒钟内,即NDIS调用CheckForHangHandler后。这个功能是微软在PC97规范中定义的,所以ndis3没有这个功能。
    linux对这个没有要求,novell netware对这个有要求,其它的操作系统我也不清楚。