频道栏目
首页 > 资讯 > ASP.Net > 正文

.NET 4.0网络开发入门之旅-- 我在“网” 中央(下)

10-12-11        来源:[db:作者]  
收藏   我要投稿

4 我“连网”了吗?
  
     好了,有了前面的铺垫,现在解决判断计算机连网问题水到渠成,其思路很简单:


    (1)检测一下计算机中的所有网络接口状态,只要都为“Down”,没说的,肯定没连网。
    (2)从状态为“Up”的网络接口中选一个(注意排除掉环回接口Loopback),获取其网关和DNS服务器地址,先Ping一下它的网关,如果能Ping通,再Ping一下DNS服务器,看看能不能Ping通。
    如果网关Ping不通,就换一个“Up”的网络接口试一试,重复上述过程,直到检测完了所有“Up”的网络接口。

    现在结果呼之欲出了:
    (1)只要有一个网络接口可以Ping通网关,则“本计算机肯定已连上本地网络。”
    (2)只要有一个网络接口可以Ping通DNS,则“本计算机的本地网络设置没有问题。”除非DNS服务器本身故障(应该发生机率不高)或由于你欠费之类的账号被限制,则“本计算机联上互联网应该没问题”。
    (3)为了真正确认已联上互联网,Ping一个“Well-Known”的网址,比如“百度”,能Ping通则100%确信可以上网了。

    注意:
    某些网站不响应Ping数据包,比如笔者发现微软公司主机就不理会Ping数据包,对其主机的Ping操作将以“超时(TimeOut)”收场。
   
    有的朋友看到这里,不禁会说:


     你这不是多此一举了吗?一上来直接Ping一个互联网主机,不就知道能不能上网了吗?


    呵呵,这怎么说呢?不能上网的原因太多了,如果你的网络应用程序能告之用户更详细的信息:

    无法连接网关,请检查你的网络设置
    无法连接DNS服务器,您所指定的DNS服务地址“192.168.1.1”可能有误,或者是DNS服务器故障……
    是不是更有助于用户定位网络问题?
    我在示例程序中写了一个IsOnline方法实现了前述的连网检测逻辑:

 
static   bool  IsOnline()
{
     if  (NetworkInterface.GetIsNetworkAvailable()  ==   false )
         return   false ;   // 所有网卡都是“Dwon”的
     // 选出“Up”的网卡,并且排除掉环回接口
    var query  =  from nic  in  NetworkInterface.GetAllNetworkInterfaces()
                    where  nic.OperationalStatus  ==  OperationalStatus.Up  &&
                   nic.NetworkInterfaceType  !=  NetworkInterfaceType.Loopback
                   select nic;
     foreach  (var nic  in  query)
    {
         // 先Ping网关
        Ping pinger  =   new  Ping();
         bool  GatewayReady  =   false ;
         foreach  (GatewayIPAddressInformation GatewayAddr  in
            nic.GetIPProperties().GatewayAddresses)
        {
            PingReply reply  =  pinger.Send(GatewayAddr.Address);
             if  (reply.Status  ==  IPStatus.Success)
            {
                GatewayReady  =   true ;
                 break ;
            }
        }
         if  (GatewayReady  ==   false )
             continue ;  // 所有网关都不通,不再进行下一步测试,直接检测下一个网卡
         // 网关Ping通了,可以Ping DNS
         foreach  (IPAddress addr  in  nic.GetIPProperties().DnsAddresses)
        {
            PingReply reply  =  pinger.Send(addr);
             if  (reply.Status  ==  IPStatus.Success)
            {
                 return   true ;
            }
        }
    }
     return   false ;
}

     上述代码中除了没有完成Ping一个“Well-Known”的真实互联网之外,其余的工作都已完成。


    IsOnLine方法返回“True”时,表示本地网络可以Ping通DNS,否则,返回“False”,你可以修改这个方法,让其依据具体情况返回更详细的信息(比如是哪个网卡的网关还是DNS不能Ping通)。

   5 让我们“并行”起来!

    现在再来一点“Cool”的。

    仔细考虑一下我们的“连网”判断逻辑,不难发现这些Ping操作是可以并行执行的,如果能使用多个线程同时执行Ping操作,无疑可以减少得到“是否可以访问互联网”这一最终结论的时间。

    我们可以将IsOneLine方法转换为多线程版。
    

   使用独立的线程执行每个网络接口的Ping操作,必须等待Ping网关的线程执行结束之后,依据其执行结果再决定是否新开一个线程执行Ping DNS的操作。
    当有一个网卡可以Ping通DNS时,应该通知其它线程停止工作,因为“能否上网”的结论已经得出了。

    这里面其实涉及到不少比较复杂的线程同步问题,需要用到多个线程同步对象,并且还涉及到如何中途取消一个线程执行的问题,我在《.NET 4.0面向对象编程漫谈 》的《应用篇》中,花了100多页的篇幅讲多线程,其中介绍了.NET 4.0基类库中几乎所有的线程同步对象的用法,并大力推荐推荐使用.NET 4.0的“线程统一取消模型”(参看《应用篇》的16.5 《线程统一取消模型》)来中途取消一个线程的执行。

    读者您能否将IsOneLine方法转换为多线程版,是一块检测您是否真正掌握了多线程技术的试金石。

    在这里,我想向读者介绍如何直接使用TPL(任务并行库)而不是线程达到目的。

    需要仔细分析一下IsOnLine的处理逻辑,看看哪些部分是可以并行的,这些并行操作间有怎样的合作关系。

    很明显,对于多个网络接口的连接检测工作完全是可以并行的,这是第一个任务并行点。


    其次,一个网络接口一般只有一个网关,不需要并行,但一个网络接口可能会有两个以上的DNS服务地址,很明显,这是第二个任务并行点。


    第三,在同时运行的多个并行任务之间,任何一个得到“互联网可达”最终结果的并行任务,需要通知其他任务提前中止执行。

    经过以上考虑,使用并行循环(Parallel.ForEach)而不是Task对象是更合理的选择。Parallel.ForEach可以并行执行一个循环,并且通过ParallelLoopState对象可以提前中止循环,还可以“通知到”其他工作线程。

    以下是使用任务并行库实现的IsOnLine版本:


 
static   bool  IsOnlineUseTPL()
{
     if  (NetworkInterface.GetIsNetworkAvailable()  ==   false )
         return   false ;
 &n

相关TAG标签
上一篇:邂逅IPv6 - 扫盲 - IP地址篇
下一篇:“.NET 4.0 网络开发入门之旅系列文章”—— IP 知多少?(下)
相关文章
图文推荐

关于我们 | 联系我们 | 广告服务 | 投资合作 | 版权申明 | 在线帮助 | 网站地图 | 作品发布 | Vip技术培训 | 举报中心

版权所有: 红黑联盟--致力于做实用的IT技术学习网站