标题：ENUM
简介
ENUM是IETF的电话号码映射工作组（Telephone Number Mapping working group, 简称ENUM）定义的一个协议——RFC2916，RFC2916的题目为“E.164号码和域名系统（E.164 Number and DNS）”。它定义了将E.164号码转换为域名形式放在DNS服务器的数据库中的方法，每个由E.164号码转化而成的域名可以对应一系列的统一资源标识（Uniform Resource Identifier），从而使国际统一的E.164电话号码成为可以在互联网中使用的网络地址资源。ENUM可以利用电话号码来查找注册人（Registrant）的电子邮件、IP电话号码、统一消息、IP传真或个人网页等多种信息。E.164号码是传统电信网络中使用的重要资源，DNS系统是互联网的重要基础，ENUM将两者结合起来，有益于传统电信服务向基于IP包交换的方向发展，ENUM是对促进两网最终融合具有重要意义的技术。 
ENUM是一个新标准，尚未广泛推广，但它将带来电信和个人移动性行业的一场新革命。
工作过程
ENUM定义了如下过程，将电话号码映射为DNS系统中的记录： 
一个E.164号码由以下几个部分组成，不同部分之间可以用“-”、“.”或空格等连接：  ENUM　　+国家码（1～3位数字）-地区码（n位数字）-电话号码（15-n位数字）。 
例如：北京的一个电话号码写成标准的E.164格式应是：+86-10-62618501 
第一步，将一个电话号码处理成一个标准的E.164号码的格式，如： +86-10-62618501 
第二步，去掉除了最左端的“+”外的所有连接符，变成： +861062618501 
第三步，去掉“+”号，并将号码翻转： 105816260168 
第四步，在每个数字之间加上域名分割符“.”： 1.0.5.8.1.6.2.6.0.1.6.8 
第五步，在上面的数字串末尾加上“.e164.tld”： 1.0.5.8.1.6.2.6.0.1.6.8.e164.tld 
这样，1个电话号码就变成了DNS中的域名形式。每个E.164号码形成的域名可以对应多条网络资源记录，称为统一资源标识（URI），它是采用另一个IETF建议RFC 2915定义的格式，称为“名称权威指针”（Naming Authority Pointer，简称NAPTR）。 
RFC2915定义书写的格式： 
Domain TTL Class Type Order Preference Flags Service Regexp Replacement 
例如，下面就是ENUM的DNS服务器的书写格式: 
$ORIGIN 1.0.5.8.1.6.2.6.0.1.6.8.e164.cn. 
IN NAPTR 10 10 “u”“mailto+E2U”“!^.*$!mailto:lee@cnnic.net.cn!” 
IN NAPTR 10 10 “u”“http+E2U”“!^.*$!http://likecloud.cnnic.net.cn!”. 
IN NAPTR 10 10 “u”“sip+E2U”“!^.*$!sip://likecloud.cnnic.net.cn!”. 
IN NAPTR 10 20 “u”“sip+E2U”“!^.*$!sip:fengw@cnnic.net.cn!”.
ENUM的典型应用
为了说明ENUM的用途，我们可以看以下这个利用ENUM建立的一个由PSTN用户发起的到基于IP网络的终端的呼叫，其典型的流程如图1所示： 
步骤1：发端用户拨E.164号码，拨号的方式由各国自己规定，如长途呼叫拨前缀“0”，国际呼叫拨前缀“0  图10”等； 
步骤2：PSTN的业务提供者根据呼叫发起的位置等因素将呼叫转至相应的网关；
步骤3：该网关必须包含ENUM功能，它能够将用户所拨的数字按照规定的规则转换成ENUM的域名形式。如果用户拨的号码不是全号，则网关应能够将丢失的数据补齐，这样才能够形成一个完整有效的域名。例如：用户拨的号码为：32341234，完整的号码应是：+8610323412343。然后网关在ENUM的DNS服务器中查找该域名； 
步骤4：DNS返回与该域名相关的所有业务记录; 
步骤5：网关在DNS中查找规定主机的地址记录; 
步骤6: DNS返回规定主机的SIP服务器IP地址; 
步骤7: 通过基于IP的网络将该呼叫接续到指定的IP地址； 
步骤8：SIP服务器将呼叫接续到规定用户的用户代理客户机上。当目的方应答时，必须将应答监视返回给发端本地交换机。 
在以上的例子中使用的是SIP客户机，在实际应用中也可以使用其它的客户协议（如H.323）。 
基于ENUM的从一个IP电话向PSTN电话发起呼叫的过程见图2。 
如果例子中第3步返回的ENUM资源记录是PSTN中的固话号码，那么呼叫将被转接到一部PSTN的电话机上。这个例子显示出ENUM实际具有传统电信网中“呼叫转移”的功能。 
ENUM注册服务本身也是一项可以发展的业务，现在的电话号码管理机构、电信服务提供商都可以开展此项业务。ENUM注册服务除了上面的电话号码注册流程外，还应包括电话号码注册为ENUM域名后的所有者变更、暂停服务、更改记录、撤销、计费、欠费等处理流程。
服务体系结构
ENUM的DNS服务提供是一个全球性的三层服务体系结构，在顶层（Tier 0）是维护E.164中分配的国家码（包括地理国家码、网络码、全球服务码和成组国家码）形成的域名映射到相应的国家ENUM顶级域名服务器地址的记录，在中间层(Tier 1)为每个国家内部的ENUM顶级DNS服务器，负责管理电话号码域名映射到相应资源记录解析服务器，底层（Tier 2）DNS服务器负责真正将电话号码解析到相应的服务记录。这样一种体系结构的目的主要是保证全球ENUM的DNS服务的统一性和互通性，真正使ENUM成为一种全球访问的网络寻址资源。ENUM的Tier 0注册机构（Registry）是全球唯一的；一般地，每个国家的Tier 1注册机构也是唯一的，使用集成编码方案的地区（Integrated Numbering Plan Area，如国家码1）需要通过有关国家专门的讨论达成一致的方案；Tier 2注册机构可以有多个。
ENUM 管理政策讨论
ENUM的实现既涉及传统电信网,又涉及互联网。传统电信网具有较严格的管制，而互联网的管理则较为开放，因此如将传统电信网的号码资源插入到互联网的DNS系统中，必然会涉及到管理方面的问题。如果不建立一个完善、严谨的管理机制，ENUM的实施可能会对现有传统电信网业务带来负面影响。因此，国际电联针对ENUM讨论的中心议题都围绕在ENUM实现过程中的管理展开。 
在ENUM的实现过程中能否建立完善的管理机制以避免对E.164号码资源的滥用是非常重要的，它是各国做出将自己管辖的E.164号码资源插入到DNS系统的决定时考虑的一个十分重要的问题。选择一个合适的TLD来实现ENUM是建立这样一个管理机制的核心部分。 
经过对ENUM相关问题的多次讨论，业界在以下两个方面达成了共识： 
1． 在全世界范围内建立唯一的DNS树来实现ENUM业务。如果分别在不同的顶级域名下建立不同的DNS树进行E.164号码翻译，E.164号码资源会被配置到不同的DNS系统中，这会导致E.164号码资源管理的失控，并带来E.164号码资源在不同的DNS系统中不一致的问题。 
2． 由ITU-T负责向E.164/ENUM根域的DNS管理者提供已经分配的E.164的国家码的信息。是否将一个国家码包含在ENUM DNS系统中是各成员国的权力，如果一个国家同意将它所管辖范围内的E.164号码资源插入到ENUM的DNS系统中，它就需要将这个决定通知ITU-T，然后ITU-T再授权给ENUM的DNS系统将该国家码插入。 
在最近两次ITU-SG2的会议上（2001年9月和2002年2月），对ENUM实现过程中TLD的选择问题进行了热烈的讨论。中国、法国、德国的同行坚持，应该由一个中立的、公正的国际组织来实现ENUM，而美国则支持采用“.ARPA”作为实现ENUM的TLD。
ENUM 的未来
ENUM对市场有巨大的潜在影响。对电信运营商而言，ENUM为电信服务商提供了新的定位和转接方式，为电信运营商充分利用互联网提供服务创造了有利的技术条件，并可以有效地促进其传统电信业务与基于Internet的业务的充分融合。ENUM有利于基于纯IP网络通信方式的普及，解决了从电话号码到IP终端设备寻址的问题，使电话号码可以同样用于基于IP包交换的电信业务。目前，英国的BT公司、法国的France Telecom公司、瑞典的Telia公司、美国的NeuStar公司、WorldCom公司、日本的NTT公司等都对ENUM技术表现出极大的兴趣，准备在2002年开展基于ENUM业务的试验。 
关于ENUM的技术标准也是ENUM发展的重要问题。IETF的ENUM工作组目前正在积极进行有关ENUM服务技术标准的制订。在近期修改完成的工作计划中，2002年6月前要完成对RFC 2916的修改，以支持动态发现域名系统标准;2002年7月要完成ENUM注册和服务提供方面的技术标准；2002年8月前要完成ENUM服务中的保护安全和隐私方面的技术标准。美国多个电信运营商、设备制造商、互联网络服务商和政府机构共同发起成立了ENUM论坛组织，专门研究ENUM在美国的管理和技术问题，AT&T、WorldCom、Cisco等公司都是该论坛的成员。该论坛的目标是在2002年夏季前完成ENUM在美国国内的DNS服务提供方案。 
ENUM同样为通信网络设备制造商提供了发展机会，通过提供支持ENUM查询功能的产品和ENUM服务设备，可以增加其产品的市场竞争力，扩大利润的来源。ENUM可以把多种通信服务和一个电话号码绑定在一起，利用同一个号码通过不同的通信方式和一个人联系，ENUM的发展将有利于支持多种通信协议终端发展。 
ENUM将带来个人通讯方式的巨大改变。现在每个人的名片上有越来越多的联系方式，如电话号码、传真号码、手机号码、传呼号码、电子邮件地址、个人主页、语音信箱等等，要想让别人记住自己所有的联系方式变得越来越困难，ENUM提供的服务将有效解决这个问题。只要申请者将自己的电话号码加入ENUM的数据库中，并输入自己的各种联系方式，那么别人只要记住他的电话号码，就可以从不同的终端上以不同的方式与他进行联系。用户也可以为自己的各种联系方式设置一定的规则，使别人可以从不同地点、不同时间以不同的方式与他联系。可以让他出差的时候打来的电话都自动转到电子邮箱或转到个人主页的留言簿里，也可以方便地用PC机或IP电话和PSTN网上的电话通话。 
ENUM在未来将拥有巨大的市场。为了使未来的ENUM市场成为一个公平、有序的市场，必须认真考虑ENUM管理和实现的各种问题。国内在信息产业部领导下，信息产业部电信研究院、中国互联网络信息中心等单位已经开始实施有关的ENUM研究计划，对ENUM在我国实现的管理和技术问题进行分析探索，目标是为ENUM在我国的长远发展找到一条可行的道路。ENUM研究中的一项重要工作是开展ENUM业务的试验，这项工作需要电信运营商、设备制造商、域名管理机构、电信标准研究机构等方面的广泛参与和配合。目前ENUM试验的准备工作已经开始，目标是用一年左右的时间搭建一个ENUM业务试验平台，并开展各种可能的ENUM业务试验。

定义和说明
1. 枚举类型定义的一般形式为： 
enum 枚举名{ 枚举值表 }; 
在枚举值表中应罗列出所有可用值。这些值也称为枚举元素。 
例如： 
该枚举名为weekday，枚举值共有7个，即一周中的七天。凡被说明为weekday类型变量的取值只能是七天中的某一天。 
2. 枚举变量的说明 
如同结构和联合一样，枚举变量也可用不同的方式说明，即先定义后说明，同时定义说明或直接说明。 
设有变量a,b,c被说明为上述的weekday，可采用下述任一种方式： 
enum weekday{ sun,mon,tue,wed,thu,fri,sat }; 
enum weekday a,b,c; 
或者为： 
enum weekday{ sun,mon,tue,wed,thu,fri,sat }a,b,c; 
或者为： 
enum { sun,mon,tue,wed,thu,fri,sat }a,b,c;
赋值和使用
枚举类型在使用中有以下规定： 
1. 枚举值是常量，不是变量。不能在程序中用赋值语句再对它赋值。 
例如对枚举weekday的元素再作以下赋值： 
sun=5; 
mon=2; 
sun=mon; 
都是错误的。 
2. 枚举元素本身由系统定义了一个表示序号的数值，从0开始顺序定义为0，1，2…。如在weekday中，sun值为0，mon值为1，…,sat值为6。 
【例11.10】 
main(){ 
enum weekday 
{ sun,mon,tue,wed,thu,fri,sat } a,b,c; 
a=sun; 
b=mon; 
c=tue; 
printf("%d,%d,%d",a,b,c); 
} 
说明： 
只能把枚举值赋予枚举变量，不能把元素的数值直接赋予枚举变量。如： 
a=sun; 
b=mon; 
是正确的。而： 
a=0; 
b=1; 
是错误的。如一定要把数值赋予枚举变量，则必须用强制类型转换。 
如： 
a=(enum weekday)2; 
特别注意：在VS2010等编译器中，强制转换格式应为：(weekday)2，如果前面加上了enum，编译时会出现“类型重定义”的错误。
其意义是将顺序号为2的枚举元素赋予枚举变量a，相当于： 
a=tue; 
还应该说明的是枚举元素不是字符常量也不是字符串常量，使用时不要加单、双引号。 
【例11.11】 
#include <stdio.h>
int main(){ 
enum body 
{ a,b,c,d } month[31],j; 
int i1; 
j=a; 
for(i1=1;i1<=30;i1++){ 
month[i1]=j; 
j = (enum body)((int)j + 1); 
if (j>d) j=a; 
} 
for(i1=1;i1<=30;i1++){ 
switch(month[i1]) 
{ 
case a:printf(" %2d %c\t",i1,'a'); break; 
case b:printf(" %2d %c\t",i1,'b'); break; 
case c:printf(" %2d %c\t",i1,'c'); break; 
case d:printf(" %2d %c\t",i1,'d'); break; 
default:break; 
} 
} 
printf("\n"); 
}
3. 如果枚举值与一些关键字冲突，例如：
enum course{begin, then, end};
由于程序有可能使用了iostream，并且使用了命名空间std，这时如果直接使用end进行赋值就有可能出现“不明确”符号的错误。解决此问题，有两个方法：
（1）定义枚举值时应避免使用常用关键字，可以加前缀进行区分
例如：enum course{e_begin, e_then, e_end};
（2）可以枚举值前面加入枚举类型：course::end
Enum的用法
Enum是enumeration(列举)的简写形式,包含在java.lang包中.熟悉C, C++, C#, 或 Pascal人应该对列举有所了解,先看个例子: public enum Season { winter, spring, summer, fall }
一个enum是定义一组值的对象,它可以包括零个或多个值成员.它是属于enum类型的,一个enum对象中不可有两个或多个相同的属性或值.在次之前的java程序员一般是 用接口的方法实现列举的,如 :
public interface Season {
static winter = 0;
static spring = 1; //etc..
}
引入了enum的java的列举的编写方便了许多,只须定义一个enum型的对象.enum对象的值都回自动获得一个数字值,从0开始,依次递增.看一个比较简单的enum实现的例子:
EnumDemo.java
package net.javagarage.enums;
/*
We can loop over the values we put into the enum
using the values() method.
Note that the enum Seasons is compiled into a
separate unit, called EnumDemo$Seasons.class
*/
public class EnumDemo {
/*declare the enum and add values to it. note that, like in C#, we don't use a ; to
end this statement and we use commas to separate the values */
private enum Seasons { winter, spring,
summer, fall }
//list the values
public static void main(String[] args) {
for (Seasons s : Seasons.values()){
System.out.println(s);
}
}
}
运行上述代码你回得到 以下结果:
winter
spring
summer
fall
Enum的属性调用:
下面的代码展示了调用enum对象的方法,这也是它通常的用法:
package net.javagarage.enums;
/*
File: EnumSwitch.java
Purpose: show how to switch against the values in an enum.
*/
public class EnumSwitch {
private enum Color { red, blue, green }
//list the values
public static void main(String[] args) {
//refer to the qualified value
doIt(Color.red);
}
/*note that you switch against the UNQUALIFIED name. that is, "case Color.red:" is a
compiler error */
private static void doIt(Color c){
switch (c) {
case red:
System.out.println("value is " + Color.red);
break;
case green:
System.out.println("value is " + Color.green);
break;
case blue:
System.out.println("value is : " + Color.blue);
break;
default :
System.out.println("default");
}
}
}
为enums添加属性和方法
enums也可以象一般的类一样添加方法和属性,你可以为它添加静态和非静态的属性或方法,这一切都象你在一般的类中做的那样.
package net.javagarage.enums;
/*
File: EnumDemo.java
Purpose: show how to use an enum that also defines its own fields and methods
*/
public class EnumWithMethods {
//declare the enum and add values to it.
public enum Season {
winter, spring, summer, fall;
private final static String location = "Phoenix";
public static Season getBest(){
if (location.equals("Phoenix")) 
return winter;
else
return summer;
}
public static void main(String[] args) {
System.out.println(Season.getBest());
}
}
就是这么的简单.但是有一点是需要注意的,那就是enums的值列表必须紧跟在enum声明,不然编译时将会出错.
Enums构造函数:
和类一样enums也可以有自己的构造函数,如下:
package net.javagarage.enums;
public class EnumConstructor {
public static void main(String[] a) {
//call our enum using the values method
for (Temp t : Temp.values())
System.out.println(t + " is : " + t.getValue());
}
//make the enum
public enum Temp {
absoluteZero(-459), freezing(32),
boiling(212), paperBurns(451);
//constructor here
Temp(int value) {
this.value = value;
}
//regular field?but make it final,
//since that is the point, to make constants
private final int value;
//regular get method
public int getValue() {
return value;
}
}
}
输出结果是:
absoluteZero is : -459
freezing is : 32
boiling is : 212
paperBurns is : 451
尽管enums有这么多的属性,但并不是用的越多越好,如果那样还不如直接用类来的直接.enums的优势在定义int最终变量仅当这些值有一定特殊含义时.但是如果你需要的是一个类,就定义一个类,而不是enum.