“.NET 4.0 网络开发入门之旅系列文章”—— IP 知多少?(上)

“.NET 4.0 网络开发入门之旅系列文章”——

          IP 知多少?(上)

 

注:

    这是一个针对网络开发领域初学者的系列文章,可作为《.NET 4.0 面向对象编程漫谈 》一书的扩充阅读,写作过程中我假设读者可以对照阅读此书的相关章节,不再浪费笔墨重复介绍相关的内容。

    对于其他类型的读者,除非您已经有相应的.NET 技术背景与一定的开发经验,否则,阅读中可能会遇到困难。

    我希望这系列文章能让读者领略到网络开发的魅力!

    另外,这些文章均为本人原创,请读者尊重作者的劳动,我允许大家出于知识共享的目的自由转载这些文章及相关示例,但未经本人许可,请不要用于商业盈利目的。

      本文如有错误,敬请回贴指正。

    谢谢大家!

 

                                                          金旭亮

=================================================

 

 

 

===================================================       

    互联网连接了不可计数的计算机,如何区分它们是一个必须认真考虑的问题,正如人使用“姓名”进行区分一样,每一台直接连上互联网的计算机也必须有一个唯一的标识,不然,在互联网上传播的信息,如何找到它预期的接收者?

1.       IPv4IPv6

         IP地址正是用于区分直接连接在互联网上计算机的一种手段,当前广泛使用的IPv4中,使用4个字节来标识互联网主机,比如百度的IP地址就是:61.135.169.105,不允许两台直接连上互联网的计算机拥有相同的IP地址,否则,互联网就乱套了,这很容易理解。

         IPv4最大的问题是地址数有限,而互联网又要求所有连网主机都必须有不同的IP地址,在当前连上互联网的各种信息设备“爆炸”式增长的时代,地址很快就不够用了,为了节约,人们想出了种种变通的方法,最常见的就是NATNetwork Address Translation),一个子网内的计算机中,只能有少数几台(通常只有一台)可以直接连上互联网,不同子网范围内的主机IP地址可以重复,当子网内部的计算机需要访问互联网时,它们需要由本子网中直接连上互联网的计算机“转发”。

         看上去NAT虽然不错,可以解决IPv4地址不够用的问题,但它也有缺点:内网主机访问互联网很方便,当互联网上的主机要访问内网计算机就麻烦了,因为内网的计算机其IP地址并非“真正”的互联网地址,这样子的两台计算机连接必须借助于其他手段(比如由另一台专用计算机进行外网内网地址转换),很麻烦。

         最终的解决方案是IPv6,它把地址扩充为128位,采用16进制表达,一个例子如下:

    2001:db8:2000:240:290:27ff:fe24:c19f/64

    最后的“/64”表示前64为网络标识,剩余的64位(128-64=64)为主机标识。

    IPv6提供了“海量”的地址空间,使用它,所有互联的设备都可以拥有一个“全球”(甚至是“全太阳系”、“全银河系”)唯一的地址,NAT这种小聪明就不再需要了。

    尽管IPv6很好,但目前IPv4仍是主流,大量的网络应用软件都使用IPv4,我也不知道,IPv6要多久才能彻底地把IPv4送进技术发展史博物馆。

    其实在网络开发中,除了IPv4和IPv6,还有其他种类的地址。.NET基类库提供了一个AddressFamily枚举来列举这些“地址类型家族”:

 

public   enum  AddressFamily
{
        Unknown 
=   - 1 ,   //  Unknown address family.
        Unspecified  =   0 //  Unspecified address family.
        InterNetwork  =   2 // Address for IP version 4.
        InterNetworkV6  =   23 // Address for IP version 6.
       
// ……
}


    AddressFamily定义了“一堆”枚举值,好多地址类型相信大多数人连听都没听说过,多用于特定的领域,还有些地址类型是“历史遗留问题”,在计算机网络早期发展史中出现,现在很少再用了,就留给有“考古”癖好的朋友们去探索吧。在.NET开发中,我们真正用到的就是AddressFamily. InterNetworkAddressFamily. InterNetworkV6,分别代表IPv4IPv6

2.       .NET开发中使用IP地址

         .NET基类库中使用IPAddress代表一个IP地址(图1):

 

“.NET 4.0 网络开发入门之旅系列文章”—— IP 知多少?(上)_第1张图片
 

1

     如图1所示,IPAddress定义了一些字段,这些字段代表特殊的IP地址,其值如下:


IPAddress.Any:  0.0 . 0.0
IPAddress.IPv6Any:      ::
IPAddress.IPv6Loopback: ::
1
IPAddress.Loopback:     
127.0 . 0.1
IPAddress.None: 
255.255 . 255.255
IPAddress.IPv6None:     ::
IPAddress.Broadcast:    
255.255 . 255.255


    简要解释一下:

    当Socket(套接字) 使用有“Any”字样的地址时,它将监听本主机上所有网络接口(Network Interface,后面文章会介绍它)。“Any”地址中的所有位均为0,IPv6简写为“::”,IPv6中,“::”是“一连串0”的压缩表示法。

    在实际开发中,我们可以将一个套接字绑定(Bind)到一个“Any”地址,当程序运行时,Windows操作系统会自动为其绑定到一个合适的本机IP地址。

    对应地,包含有“None”的地址,则套接字不监听任何一个网络接口。

    注意IPv4与IPv6的“None”地址约定是不同的。IPAddress.IPv6None的值与IPAddress.IPv6Any的值一样(所有位均为0),但却是两个不同的IPAddress对象,上述输出结果其实是调用IPAddress的ToString()方法得到的。

         当获取了一个IPAddress对象之后,可以调用它的toString方法获取它的经典表示法(如“127.0.0.1”),也可以调用GetAddressBytes方法获取它的十六进制表示形式:

 

//  输出IP地址的经典形式和十六进制形式
public   static   void  PrintIPAddress(IPAddress ipAddress)
{
    Console.WriteLine(ipAddress.ToString());
    Byte[] bytes 
=  ipAddress.GetAddressBytes();
    Console.WriteLine(BitConverter.ToString(bytes));
}


    上述代码中的BitConverter要注意一下,它可以很方便地对字节数组进行各种操作,在网络应用程序中很有用。

    IPAddress.None和IPAddress.Broadcast的值都是“255.255.255.255”,表示其地址位全为1,这种地址通常代表“广播”,表示要把数据发给互联网上的所有设备。很明显,这只是一种“幻想”,通常路由器不会转发这种类型的数据包,否则,一些“坏人”不断地“广播”数据包,整个互联网将象北京一样,成为“首堵”和“全球性等待(WWW:World Wide Wait)”。

    最有趣的是IPAddress.Loopback和IPAddress.IPv6Loopback,我们通常称其为“环回接口”,这是一个虚拟的“网卡”,代表本机。发给“环回接口”的数据包,不会真的跑到互联网上,而是直接给本地主机“内部消化”了。在Windows平台上,Web和网络开发中中常见的“localhost”,还有一个“.”,其实都对应着这个环回接口,代表本地主机。比如,我们可以使用“.\SqlExpress”访问安装于本机的SQL Server数据库。

 

3. 怎样知道特定计算机的IP地址?

    .NET基类库中有一个Dns静态类,可以完成这个工作(图2):

 

“.NET 4.0 网络开发入门之旅系列文章”—— IP 知多少?(上)_第2张图片 

  2

 

 

         Dns提供了一堆的静态方法完成各种常用的IP地址查询功能。

         比如,以下代码获取本地主机名称:

         String LocalhostName = Dns.GetHostName();

         以下代码获取微软公司主机的IP地址:

         IPAddress[] ips = Dns.GetHostAddresses("www.microsoft.com");

         将上述两句“组合起来”,我们就可以获取本地主机的所有IP地址:

         IPAddress[] ips = Dns.GetHostAddresses(Dns.GetHostName());

         如果希望获取更详细的信息,可以使用Dns的以下方法:

         public static IPHostEntry GetHostEntry( string hostNameOrAddress )

         上述代码中的IPHostEntry.NET基类库中的另一个类(图3),可以看到通过它不仅可以获取指定主机的所有IPv4IPv6地址,还可以知道它的主机名(HostName)和别名(Aliases)。

 

 

 

“.NET 4.0 网络开发入门之旅系列文章”—— IP 知多少?(上)_第3张图片

 

3

 

以下是使用GetHostEntry 直接访问微软网站得到的主机信息:

 


主机名称:lb2.www.ms.akadns.net
主机www.microsoft.com拥有以下IP地址:
    AddressFamily:InterNetwork    Address:
207.46 . 170.10
    AddressFamily:InterNetwork    Address:
65.55 . 21.250
    AddressFamily:InterNetwork    Address:
207.46 . 170.123
    AddressFamily:InterNetwork    Address:
65.55 . 12.249

 

注意:

         Dns类中有些方法被废弃(Obsolete)了,使用它时注意一下编译器给出的警告信息。

 

         为了方便起见,我们将获取本地主机IPv4地址的功能封装为一个静态方法,并将其放入到一个AddressHelper静态类中:

 

 

代码
public   static   class  AddressHelper
 {
        
public   static  IPAddress[] GetLocalhostIPv4Addresses()
        {
            String LocalhostName 
=  Dns.GetHostName();
           IPHostEntry host 
=  Dns.GetHostEntry(LocalhostName);
            List
< IPAddress >  addresses = new  List < IPAddress > ();
            
foreach  (IPAddress ip  in  host.AddressList)
            {
                
if  (ip.AddressFamily  ==  AddressFamily.InterNetwork)
                    addresses.Add(ip);
            }
            
return  addresses.ToArray();
        }
       
// ……
}

 


         再把上述这个类添加到一个 MyNetworkLibrary 类库中,此类库将用于封装一些常用的功能,后续文章中的示例将直接使用它。

==============================

一次发不完,分两次发:

 

 

 

 

 

你可能感兴趣的:(.net)