最新
推荐
2014年高等教育信息化十大“关... 01-04 教育部成立教育信息化专家组 12-24
CERNET第二十一届学术年会 11-24 李志民:互联网促进人类文明迈... 11-15
| 下面研究导致程序协议相关的主要因素:
(1) 对地址族无根据的假定。在使用数据结构存储地址或对地址进行分析处理时,为了编程的方便,无根据地假定地址是IPv4或IPv6的。in_addr, sockaddr_in, in6_addr, sockaddr_in6这四个存储地址的结构体都包含了对地址族的假定。因些应该避免随意使用这些结构体。sockaddr_storage虽然是协议无关的地址结构,但它既能表示IP地址,又能表示传输层的端地址(IP地址和端口),使用时通常要进行强制类型转换,绕过了编译期的类型安全检查,这种模糊性会增加编程出错的可能性。而且它有128个字节长,显得十分臃肿。 (2)使用只支持IPv4的函数。有些socket API由于历史原因只支持IPv4,应该避免使用。这样的函数有:DNS函数(gethostbyname, gethostbyaddr),地址与字符串转换函数(inet_ntoa, inet_addr)。 (3)参数中需要对地址族有先验知识的函数。inet_pton和inet_ntop两个函数虽然同时支持IPv4和IPv6,但它们的接口需要传入地址族类型。如果预先把地址族类型写死在程序里,将产生协议相关性,因此不推荐使用这两个函数。 (4)参数中含有地址的函数。这些函数一般都使用sockaddr*作为参数类型,它们自身是协议无关的,但如果函数调用方使用了协议相关的地址结构,将产生协议相关性。这样的函数主要有:bind, connect, accept, recvfrom, sendto, getsockname, getpeername。使用这些函数需要小心。 (5)使用了协议相关的socket 选项。有些socket选项对于IPv4和IPv6来说是不同的,直接使用它们将产生协议相关性。常见的这类选项有:跳数设置、加入退出ASM/SSM组播组等。 为了消除这些导致协议相关的因素,本文实现了一个协议无关socket类库。首先使用IPAddress类重新对IP地址进行了封装。IPAddress类包含一个记录地址族的成员变量,既可以表示IPv4地址又可以表示IPv6地址。IPAddress对象只有18字节。IPAddress支持以协议无关的方式从字符串解析出网络地址,而不需要提供先验的地址族信息。再用IPEndPoint对传输层的端地址进行了封装,IPEndPoint包含IPAddress和一个端口。IPEndPoint只有20字节,相比sockaddr_storage小了108字节。 DNS解析的任务由Dns类的一组静态函数完成。在函数的内部使用同时支持IPv4和IPv6的getaddrinfo和getnameinfo函数,而不使用只支持IPv4的gethostbyname和gethostbyaddr。对包含IP地址的addrinfo结构,使用IPAddressInfo类进行了协议无关的封装。 网络编程接口由Socket类实现。将常用的socket API都封装到Socket类中。所有参数中带有地址的函数,都用协议无关的IPAddress或IPEndPoint代替掉。 对于IPv4和IPv6下不同的socket选项进行统一化处理。对外提供统一的接口函数,内部根据协议族的不同选择不同的实现方式。例如传统上进行ASM/SSM组播编程,需要记住8个选项名和4个额外的数据结构,经常容易出错。但经过统一化处理后,只需要记住四个非常简单的函数: JoinGroup/JoinSourceGroup 接口的参数里只有IPAddress,不需要任何额外的结构体。这使组播编程大大简化。 5 对标准输入输出流的扩展 流传输模型是一种对数据传输系统的抽象,适用性非常广。连续访问内存中的字节串可以看成是流,对文件数据进行读写也可以通过流的方式进行,TCP传输也是一种流式的通信方式。 由于流是一种通用性很强的数据传输抽象,在各种高级编程语言的标准库中都对它提供了内置的支持,C++也不例外。 C++提供的标准输入输出流类都派生自模板类basic_iostream。对于一种数据结构来说,这样的好处是,它的输入输出函数只需要针对basic_iostream的接口写一次,而不用考虑各种不同输入输出设备之间的差异。在进行实际的输入输出操作时,执行操作的对象属于具体的basic_iostream的派生类,C++的虚函数和多态机制保证了对不同设备采用不同的处理方式。 但在C++标准库里只支持针对内存数据的stringstream和针对文件系统数据的fstream,而没有针对TCP流进行处理的网络输入输出流类。这就需要维护两套代码,分别用于处理文件流和网络流,这样既麻烦又容易出错。因此对C++标准输入输出流的实现以及扩展方法进行了研究,实现了面向网络传输的输入输出流类。 首先从basic_streambuf类派生出SockStreamBuf,实现网络传输流的缓冲区。在实现SockStreamBuf时,需要对basic_streambuf的如下几个虚函数进行改写,如表1所示。 在实现这些虚函数时需要注意:在输出缓冲区满时发送数据以释放缓冲区,或在输入缓冲区空时接收数据以填充缓冲区。除了实现基本的basic_iostreambuf接口外,针对网络传输的特点,还增加了判断tcp连接状态、设置超时等接口。 第二步,再从basic_iostream派生出SockStream。SockStream与basic_iostream最本质的不同是它的底层缓冲区是SockStreamBuf,所有对网络传输的处理都由SockStreamBuf完成,SockStream对basic_iostream的扩展仅仅是为了使用方便。例如SockStream提供的open函数,使我们可以用打开文件的方式打开一个TCP连接。例如: SockStream stream1(“166.111.8.238:23”);
此类库已经被成功地应用于一个CERNET2网络主动测量项目。 作为“CNGI大规模路由和组播技术的研究与试验”项目的一部分,在CERNET2主干网的25个核心路由器周围将部署50台服务器,每台路由器有两个服务器与之直接相连。在这些服务器上将部署用于主动测量[8]的探针程序Probe。图中上部的PMS(Probe Manager Server)服务器是专门用于集中管理这些Probe的服务器。在PMS的统一管理与控制下,Probe之间通过相互发送测量数据包对主干网的网络特性进行主动测量。PMS对外以telnet接口提供控制和数据接口。Web Server使用此接口向用户提供可视化控制和数据界面。 此系统中所有网络通信都由本类库完成。Probe之间的测量数据包传输采用IPv4、IPv6下的单播,ASM/SSM组播六种方式;Probe与PMS之间的接口采用基于TCP的二进制协议;PMS与WebServer之间采用基于TCP的文本协议:telnet。这两个接口都同时支持IPv4和IPv6。Probe和PMS都支持跨平台,同时支持Linux和Windows操作系统。 经过实验室环境下的测试运行,该系统运行正确稳定。 7 结语 本文研究了跨平台程序设计和协议无关网络编程技术,以及面向网络的标准输入输出流的实现技术。在这些技术的基础上,实现了一个跨平台协议无关的网络类库,并通过实际系统验证了该类库达到了跨平台和协议无关的设计目标,而且具有较好的易用性和健壮性。如果此类库可以得到推广使用,将会提高网络应用软件开发效率,减少跨平台程序的实现难度,增加同时支持IPv4和IPv6的应用软件数量,从而有助于IPv4向IPv6的平滑过渡。
蒋锦鹏(1984-),男,甘肃人,硕士,主要研究方向为网络体系结构,网络测量,网络流媒体。 |
版权所有:中国教育和科研计算机网网络中心 CERNIC,CERNET,京ICP备15006448号-16,京网文[2017]10376-1180号
关于假冒中国教育网的声明 | 有任何问题与建议请联络:Webmaster@staff.cernet.com