1、网络通信协议的研究及实现摘 要:网 络通信协议是为了保证计算机通过网络互相通信的一套规则和约定。计算机网络协议分类较多,其中关注最多的是 TCP/IP 协议 和 UDP/IP 协议。本文介绍了计算机协议的概念和作用,并利用 C 语言对 TCP/IP 协议和 UDP/IP 协议的工作过程进行软件实现。关键词:网络通信协议;TCP/IP;UDP/IP ;C 语言Study and Implementation of Network Communication ProtocolAbstract: Network communication protocol consists of a set of
2、rules and conventions which ensure the interaction between computers through networks. Computer network protocol can be divided into numerous categories, of which TCP/IP and UDP/IP are most mentioned. This article introduces the concept and role of computer protocol, and realizes the process of TCP/
3、IP and UDP/IP through C language.Key words: Network Communication Protocol; TCP/IP; UDP/IP; C Language1 引言通信涉及的所有部分都必须认同一套用于信息交换的规则。人们把这种认同的规则称为协议(protocol) 。这些规 定消息的格式以及每条消息所需的适当动作的一套协议称为网络协议(network protocol) 或计算机通信协议(communication protocol)1。实现这些规则的软件称为协议软件(protocol soft)。规定计算机信息交换中消息的格式和含义的协定称为通
4、信协议。本文就计算机网络协议的体系结构及其应用分析计算机网络通信协议,同时利用 C 语 言实现 TCP 和 UDP 的传输过程。最后再对未来网络协议的发展做个展望。2 计算机网络通信的简述网络协议设计一般假设协议参与者是完全服从的。网络参与各方协调一致,按照协2议的规定完成特定的任务。通信涉及的所有部分都必须认同一套用于信息交换的规则。人们把这种认同称为协议(protocol)。 这一术语也可用于 计算机通信(规定消息的格式以及每条消息所需的适当动作的一套协议称为网络协议(network protocol) 或计算机通信协议(communication protocol)。实现这些规则的软件称
5、为协议软件(protocol soft)。规定计算机信息交换中消息的格式和含义的协定称为通信协议。2.1 网络通信协议及其所起的作用在计算机网络技术中, 一般把通信规程称作协议。所谓协议, 就是人们在设计计算机网络系统时, 预先作出的一系列约定, 作为约定后, 数据通信必须完全遵照约定来进行。由于计算机网络使用的通信协议比较复杂, 协议 由语法、语义和交换规则三个部分组成,语义是通信双方要表达的内容,即协议所包含的元素, 语法是规定这些内容的表示形式, 即协议 中元素的格式交换规则是指这些元素之 间的应答关系, 也就是数据通信过程中要发生的状态的变化规则 2。数据从计算机网络中的源站发出, 到
6、目的地站的接收, 最后达到收、发双方之间的 对话或互操作, 需要经历 一系列的协议操作 2。例如 , 发送站把数据发送到线路上, 根据目的地地址, 先要经历在链路上的传输。链路是在通信节点间保证无差错传输的路径单元。每个节点收到信息后, 对它作差错检测和改正差错, 然后再发送到下一个节点。如果遇到无法改正的差错, 则退回上一个节点要求重发。目的地址包括目的地站所在的网络段号网络地址和在该网络段上的节点号节点地址,如果在某个中间节点上有多个网络分支的路径, 为使信息以最经济、快捷的路径传送。 要由该中间节点过断了路由确定,然后可能跨越多个网络, 进行端对端从发站到收站的传输, 把数据送到目的地站
7、。此后, 还可能要作端到端的差 错校验和改正。 在进行收、发站之间的交互行中的计算机程序之间的衔接进程和进程之间的连接, 语言或代码转换, 最后到达应用层, 进行应用的信息处理操作。通信 结 束后, 要进行拆除连接,释放信道的3过程。如此完成一次通信, 这其中每个阶段都需要有严格的协议作为保证。2.2 网络通信协议的分层及功能按照国际标准化组织(ISO)的建议,目前实际广泛使用的网络结构模型是开放系统互连模型(OSI)。这是一个七 层协议,包括物理 层协议 、数据 链路层协议、网络层协议、传输层协议、会话层协议、表示层协议、应用层协议 3。物理 层协议实现物理上互连系统间位流信息的透明传输,即
8、实现了一位(组)数据在两个通信实体之间的可靠传送通信,它描述了经通信介质在数据链路实体之间建立、维护和拆除物理连接。数据链路层协议主要是对高层屏蔽传输介质的特性,为网络通信实体之间提供建立、维护和释放数据链路连接的功能和手段,实现无差错的数据以帧为单位的可靠传送。网络层协议主要是为通信子网与高层结构之间提供界面连接, 其主要任 务是对通信子网实现路径选择,实现通信实体之间端-端的透明的数据传送,对高层屏蔽了数据传送经过的路径。传输层协议也称主机主机层协议,它为会话层的通信实体之间提供透明的数据传送,其主要任务是接收会话实体送来的数据,根据需要把他们分成若干比较小的单元,保证所有数据单元经下面三
9、层正确地到达另一个会话实体。会话层协议也称进程进程层协议,它通过协议提供的一组命令为网上两个进程之间的通信建立会话连接和释放会话连接,并管理它们在该连接上的对话。表示层协议以对应用实体有意义的形式提供有关信息表示的服务。这 些服务有文本压缩 、代 码转换、数据加密与解密、文件格式变换、信息格式变换、终端属性的转换等。应用层协议是用户访问网络的接口层,直接为正在通信的端点用户的应用进程服务。3 传输层通信协议的分析3.1 TCP 协议的分析传输控制协议 TCP 是 TCP/IP 协议栈中的传输层协议,它通过序列确认以及包重4发机制,提供可靠的数据流发送和到应用程序的虚拟连接服务。与 IP 协议相
10、结合,TCP 组成了因特网协议的核心。它是一种面向连接的、可靠的传输层协议 4。TCP 协议是为了在主机实现高可靠性包交换的传输协议,在计算机网络中用途很广泛。 由于大多数网络应用程序都在同一台机器上运行,计算机上必须能够确保目的地机器上的软件程序能从源地址机器处获得数据包,以及源地址计算机能收到目的计算机正确的回复,这是通过使用 TCP 的“ 端口号”完成的。网络 IP 地址和端口号相结合成为唯一的标识 ,我们称之为“ 套接字”或“端点”。 TCP 在端点间建立连接或虚拟电路进行可靠通信 5。3.2 UDP 协议的分析UDP 协议是英文 User Datagram Protocol 的缩写,
11、即用户数据报协议,主要用来支持那些需要在计算机之间传输数据的网络应用。包括网络视频会议系统在内的众多的客户/服务器模式的网络应用都需要使用 UDP 协议。 UDP 协议从问世至今已经被使用了很多年,虽然其最初的光彩已经 被一些类似协议所掩盖,但是即使是在今天, UDP 仍然不失为一项非常实用和可行的网络传输层协议 8。与我们所熟知的 TCP(传输控制协议)协议一样,UDP 协议直接位于 IP(网际协议)协议的顶层 。根据 OSI(开放系统互连)参考模型,UDP 和 TCP 都属于传输层协议。UDP 协议是一个简单的面向数据报的传输层协议,他不提供可靠性:即只把 应用程序传给 IP 层的数据发送
12、出去,但是并不能保证他们能到达目的广播和多播是基于 UDP协议的两种消息发送机制。广播数据即从一个工作站发出,局域网内的其他所有工作站都能收到它。IP 协议下,多播是广播的一种变形:IP 多播要求将对收发数据感兴趣的所有主机加入到一个特定的组。 3.3 UDP 协议的应用 既然 UDP 是一种不可靠的网络协议,那么 还有什么使用价值或必要呢?其实不然,5在有些情况下 UDP 协议可能会变得非常有用。因为 UDP 具有 TCP 所望尘莫及的速度优势。虽然 TCP 协议中植入了各种安全保障功能,但是在 实际执行的过程中会占用大量的系统开销,无疑使速度受到严重的影响。反 观 UDP 由于排除了信息可
13、靠传递机制,将安全和排序等功能移交给上层应用来完成,极大降低了执行时间,使速度得到了保证。 关于 UDP 协议的最早规范是 RFC768,1980 年发布。尽管时间已经很长,但是 UDP协议仍然继续在主流应用中发挥着作用。包括视频电话会议系统在内的许多应用都证明了 UDP 协议 的存在价值。因 为相对于可靠性来说,这些应用更加注重实际性能,所以为了获得更好的使用效果(例如,更高的画面帧刷新速率)往往可以牺牲一定的可靠性(例如,会面质量)。这就是 UDP 和 TCP 两种协议的权衡之处。根据不同的环境和特点,两种传输协议都将在今后的网络世界中发挥更加重要的作用。4 基于 C 语言的 TCP 网络
14、编程4.1 协议的功能模块设计用 C 语 言实现了基于 TCP 的服务器端和客户端程序,能实现基本的 TCP 通信 7。TCP 程序设计服务器端 客户端初始化模块功能控制模块循环控制模块服务模块初始化模块功能控制模块数据传输控制模块6图 1 功能模块图本程序由两大部分组成,包括服务器端和客户端,如图 1 所示。服 务器端包含的模块有初始模块、循环控制模块和服务模块;客户端包含的模块有初始化模块、功能控制模块和数据传输控制模块。1 服务器端1 初始化模块用于初始化各个全局变量赋初始值。初始化 Winsock,加载 Winsock 库。2 功能模块控制。该模块为其他模块提供调用的函数,包括参数获取
15、功能、用户帮助功能和错误输出功能 。3 循环控制模块。该模块用于控制服务器端的服务次数,如果服务次数超过指定的值则停止服务器。4 服务模块。该模块为客户端提供服务功能,包括接收来自客户端的数据,并发送数据到客户端。2 客户端1 初始化模块。该模块用于初始化客户端的 Winsock,加载 Winsock 库。2 功能模块控制。与服务器端一样, 该模块提供了参数获取、用 户帮助和错误输出功能。3 数据传输控制模块。该模块控制着整个客户端的数据传输,包括数据发送和接收等。74.2 系统主程序的流程图4.2.1 服务器端系统流程图开始获取参数获取成功初始化变量和 Winsock创建套接字创建成功 解析
16、主机名或者 IP 地址解析成功设置服务器地址参数侦听成功绑定成功释放资源关闭服务绑定地址与接字侦听连接循环控制结束输出相应错误信息否是否 是否是是否否是图 2 服务器端系统流程图84.2.2 客户端系统流程图3 个参数创建成功获取成功解析成功解析主机名或 IP 地址创建套接字获取参数设置服务器地址参数连接服务器开始结束连接成功释放资源关闭套接字输出连接信息发送信息到服务器端接收服务器端的响应输出相应错误信息显示用户帮助否是否否否是是否是图 3 客户端系统流程图4.3 源码分析4.3.1 服务器端主函数控制着整个程序的流程,包括套接字的创建、绑定、 侦听和释放,以及对各个9模块中函数的调用等。其
17、具体操作流程图可参见图 2。int main(int argc, char *argv)SOCKET listenfd;int err;struct sockaddr_in serverAddr;struct hostent *ptrHost;initial();GetArgments(argc,argv);InitSockets();/*创建 TCP 流套接字,在 domain 参数为 PF_INET 的 SOCK_STREAM 套接中,protocol 参数 为 0 意味着告 诉内核选择 IPPRPTP_TCP,这也意味着套接口将使用TCP/IP 协议*/listenfd = socket
18、(PF_INET, SOCK_STREAM, 0);/*如果创建套接字失败*/if (listenfd = INVALID_SOCKET)printf(“Error: out of socket resourcesn“);return 1;/*如果是 IP 地址*/if (atoi(hostName) /*将 IP 地址转换成 32 二进制表示法,返回 32 位二进制的网络字节序*/u_long ip_addr = inet_addr(hostName);/*根据 IP 地址找到与之匹配的主机名*/ptrHost=gethostbyaddr(char*)/*如果是主机名*/else/*根据主机
19、名获取一个指向 hosten 的指针,该结构中包含了该主机所有的 IP地址*/ptrHost = gethostbyname(hostName);/*如果解析失败*/if (!ptrHost)ErrorPrint(“cannot resolve hostname“);10return 1;/*设置服务器地址*/*设置地址族为 PF_INET*/serverAddr.sin_family = PF_INET;/*将一个通配的 Internet 地址转换成无符号长整型的网络字节序数*/serverAddr.sin_addr.s_addr = htonl(INADDR_ANY);/*将端口号转换成无
20、符号短整型的网络字节序数 */serverAddr.sin_port = htons(port); /*将套接字与服务器地址绑定*/err = bind(listenfd, (const struct sockaddr *) /*如果绑定失败*/if (err = INVALID_SOCKET)ErrorPrint(“Error: unable to bind socketn“);return 1;/*开始侦听,设置等待连接的最大队列长度为 SOMAXCONN,默认值为 5 个*/err = listen(listenfd, SOMAXCONN);/*如果侦听失败*/if (err = INV
21、ALID_SOCKET)ErrorPrint(“Error: listen failedn“);return 1;LoopControl(listenfd, 1);printf(“Server is downn“);/*释放 Winscoket 初始化时占用的资源*/WSACleanup();return 0;114.3.2 客户端主函数中包括套接字的创建、绑定和释放,服 务器的连接,数据的 发送、接收以及对各个模块中函数的调用等。其具体操作流程图可参见图 3。int main(int argc, char *argv)SOCKET clientfd;int err;struct sockad
22、dr_in serverAddr;struct hostent *ptrHost;char response4096;char *msg = “HELLO SERVER“;GetArgments(argc, argv);if (argc != 3) userHelp();return 1;GetArgmiients(argc,argv);InitSockets();/*创建套接字*/clientfd = socket(PF_INET, SOCK_STREAM, 0);/*如果创建失败*/if (clientfd = INVALID_SOCKET)ErrorPrint(“no more sock
23、et resources“);return 1;/*根据 IP 地址解析主机名*/if (atoi(hostName)u_long ip_addr = inet_addr(hostName);ptrHost = gethostbyaddr(char *)/*根据主机名解析 IP 地址*/elseptrHost = gethostbyname(hostName);12/*如果解析失败*/if (!ptrHost)ErrorPrint(“cannot resolve hostname“);return 1;/*设置服务器端地址选项*/serverAddr.sin_family = PF_INET;
24、memcpy(char *) serverAddr.sin_port = htons(port);/*连接服务器*/err = connect(clientfd, (struct sockaddr *) /*连接失败*/if (err = INVALID_SOCKET)ErrorPrint(“cannot connect to server“);return 1;/*连接成功后,输出信息 */printf(“You are connected to the servern“);/*发送消息到服务器端*/send (clientfd, msg, strlen(msg)+1, 0);memset(
25、response, 0, sizeof(response);/*接收来自服务器端的消息*/recv(clientfd, response, sizeof(response), 0);printf(“server says %sn“, response);/*关闭套接字*/closesocket(clientfd);/*释放 Winscoket 初始化时占用的资源*/WSACleanup();return 0;提示:由于在 TC 或者 Win-TC 中没有编译套接字的头文件,所以该程序需要在13Visual C+或者具有 Winsock 头文件的编译器中编译 。本章的服务器端和客户端程序端都已经
26、在 Visual C+6.0 中通过编译。4.4 对程序进行测试4.4.1 以默认主机名和端口号启动服务器如图 4 所示,以默认选项启动服务器端,即服 务器端 IP 地址为“127.0.1”,端口号为“9999”。如果客户端有到服务器端的连接,则在客户端会显示连接信息,信息中包括客户端的 IP 地址。图 4 中显 示的信息“Accepted connection from client at#127.0.0.1”,由于这里是在同一台主机上,则这里将显示相应的客服端 IP 地址,但前提是服务器端不是以“127.0.0.1”为地址启动,而是相应的服务器端所在主机的 IP 地址或者主机名为地址来启动
27、。启动 服务器端后,以正确的服务器端 IP 地址和端口号启动客户端,如图 5 所示。这时将在客户端显示连接信息,并显示来自服务器端的相应“ HELLO CLIENT而服务器端的连接信息则如图 4 所示。C:WINDOWSsystem32cmd.exe tcp.exeE:booksrcchap10tcpDebugtcp.exeAccepted connection from client at 127.0.0.1- 图 4 以默认主机名和端口号启动服务器同样的,在客户端以正确的服务器端主机名和端口号启动客户端,仍会正确连接,如图 6 所示,其显示的连接信息也和图 5 相同。14图 5 带正确 I
28、P 地址和端口号启 动客户端C:WINDOWSsystem32cmd.exeE:booksrcchap10tcp_clientDebugtcp_client.exe h:127.0.0.1 P:9999You are connected to the serverServer says HELLO CLIENTE:booksycchap10tcp_clientDebug_ C:WINDOWSsystem32cmd.exeE:booksrcchap10tcp_clientDebugtcp_client.exe h:computer P9999You are connected to the se
29、rverServer says HELLO CLIENTE:booksrcchap10tcp_clientDebug_ 图 6 带正确主机名和端口号启动客户端如果客户端连接 3 次服务器后,达到服务器端的最大服务次数(默认值为 3 次),服务器端将会自动关闭,如图 7 所示。4.4.2 带选项启动服务器如图 8 所示,服务器端以命令”tcp.exe-h:127.0.0.1-p:888-n:4”启动,表示服务器端的IP 地址是 “127.0.0.1”,端口号是“8888”,做多服 务次数是 4 次。15CWINDOWSsystem32cmd.exeE:booksrcchap10tcpDebugt
30、cp.exe h:127.0.0.1 P:888 n:4Accepted connection from client at 127.0.0.1Accepted connection from client at 127.0.0.1Accepted connection from client at 127.0.0.1Accepted connection from client at 127.0.0.1Last thread to finish was thread #0Server is downE:booksrcchap10tcpDebug_图 7 达到最多服务次数的服务器端C:WIND
31、OWSsystem32cmd.exeE:booksrcchap10tcpDebugtcp.exeAccepted connection from client at 127.0.0.1Accepted connection from client at 127.0.0.1Accepted connection from client at 127.0.0.1Last thread to finish was thread #0Server is down E:booksrcchap10tcpDebug_图 8 带选项启动服务器端5 基于 C 语言的 UDP 网络编程5.1 协议的功能模块设计本
32、程序有 3 大部分组成:即广播模块、多播模块部分,如图 9 所示。其中公共模 块和多播模块共享的部分,包括初始化模块、参数 获取模 块和用户帮助模块;广播模块包括广播消息模块;多播模块包括多播功能控制模块、多播消息发送模块和多播消息接收模块。16UDP 程序设计公共模块 广播模块 多播模块初始化模块用户帮助模块参数获取模块广播消息发送模块广播消息接收模块多播消息发送模块多播功能控制模块多播消息接收模块图 9 功能模块图5.2 系统流程图系统流程图如图 10 所示。程序首先初始化全局变量,包括广播(多播)地址、端楼号、发送(接收 )消息数量等,然后花圈用户提供的参数,并初始化 Winsock 初
33、始也成功则判断是进行广播还是多播程序;如果是广播,则判断是发送者身份还是接收身份,然后根据不同的身份进行相应的处理,即发送广播消息或者接收广播消息;同样地,如果是多播,也惊醒身份的判断,然后作同样的处理 9。17初始化全局变量获取参数设置标记接收广播消息 发送多播消息初始化 Winsock发送广播消息 接收多播消息成功?广播?发送?发送?成功?开始图 10 系统流程图5.2.1 广播消息发送流程图广播消息流程图如图 11 所示。程序首先创建 UDP 套接字,如果创建成功则设置广播地址;由于进行的是广播机制,所以要将套接字时针为广播类型,即 SO-BROADCAST;如果套接字选想不开设置成功则
34、可以避免向指定的广播地址广播消息了。广播结束后(即达到最多的消息条数),关闭套接字,释放占用资源。5.2.2 广播消息接收流程图广播消息的接收流程如图 12 所示。程序首先创建 UDP 套接字,如果创建成功则设置本地地址和广播地址,本地地址用于绑定套接字,广播地址是广播消息接收的地址。同发18送广播消息一样,接收消息的套接字也要设置选项,不同的是,这里将套接字设置成可重用类型的,即 SO-REUSEADDR,选项级别为 SOL-SOCKET。这样一来,在相同的本地接口及端口上可以进行多次监听,即在同一台主机上,可以启动多个消息接收端来接收广播消息,如果不设置这个选项,则在同一台主机上,只能启动
35、一个消息接收端来接收消息。套接字选拔设置成功后,绑定本地地址与套接字,即可以从广播地址接收广播消息,如果接收的消息条数达到最大限制则结束程序,关闭套接字,释放占用资源。创建 UDP 套接字设置广播地址选项输出成功信息输出错误信息创建成功?设置成功?发送成功?还可以发送?设置套接字为广播类型发送消息到广播地址关闭套接字释放占用资源开始结束否是否否是是是否创建 UDP 套接字开始创建成功?设置本地地址选项设置广播地址选项设置套接字为可重用类型创建成功?绑定套接字和本地地址接收广播消息输出接收的消息清空缓冲区还可以接收?关闭套接字释放占用资源结束否是否是是否图 11 广播消息发送流程图 图 12 广
36、播消息接收流程图195.3 源码分析主函数实现 Winsock 的初始化、广播与多播的选择以及发送者与接收者身份选择等功能,其实现流程可参见图 10。int main(int argc, char *argv)WSADATA wsd;initial();GetArgments(argc, argv);/*初始化 Winsock*/if (WSAStartup(MAKEWORD(2, 2), return -1;if(broadFlag) /*如果是执行广播程序*/if(broadSendFlag) /*以发送者身份发送消息*/broadcastSend();return 0;else /*以接
37、收者身份接收消息 */broadcastRec();return 0;20if(multiFlag) /*如果是 执行多播程序*/if(multiSendFlag) /*以发送者身份发送消息*/multicastSend();return 0;else /*以接收者身份接收消息 */multicastRec();return 0;return 0;提示:由于在 TC 或者 Win-TC 中没有编译套接字的头文件,所以该程序需要在Visual C+或者具有 Winsock 头文件的编译器中编译。本章程序已经在 Visual C+ 6.0中通过编译。5.4 运行结果本节将测试程序的运行,主要包括测
38、试不带选项启动服务、以默认选项启动广播发送和接收端、以指定选项启 动广播发送和接收端、以默认选项启动多播发送和接收端、以默认选项启动多播接收和发送接收端。21结论随着计算机网络技术的飞速发展,计算机网络的逐渐普及各种计算机网络怎么连接起来就显得相当的复杂。本文讲述了计算机网络通信协议以及对通信协议中最重要的两个传输协议TCP/IP和UDP/IP协议进行充分的原理分析和程序实现,并用C语言编程实现了两个协议的运行过程,让 人们对通信协议有更深入的了解和认识。由于时间和能力等多方面的原因,本论文难免有不足之处。但 这并不影响人们对未来网络通信发展的认识。计算机网络发展的基本趋势是开放、集成、高速、
39、移动、智能以及分布式多媒体应用。其中开放和集成是相辅相成的。开放指网络体系结构的开放和操作系统调用界面与用户操作界面的开放,开放的核心问题是标准问题 ,即各种不同厂家的计算机或网络产品能够按照统一的标准向高层提供相应的服务,这就需要标准协议的支持。因此未来网络体系结构的标准化也就是网络通信协议的标准化。没有通信协议的标准化,就不会形成标准的网络体系结构。它们相 辅相成互相促进互相发展的。参考文献1 李 雨 , 冯 迪 . 浅 析 计 算 机 网 络 通 信 协 议 J. 中 小 企 业 管 理 与 科 技 (上 旬 刊 ) , 2009(01):9-15. 2 黄 庆 , 周 文 静 . 计
40、算 机 网 络 协 议 及 其 应 用 分 析 J. 软 件 导 刊 , 2009(01):7-12. 3 孙大高. 计算机通信网络互连技术J. 计算机研究与发展 , 1994(11):40-55.4 汪齐贤. TCPIP 协议分析J. 北方交通大学学报 , 1995(01):11-23. 5 方译. TCP/IP 相关名词浅释 J. 电子产品世界 , 1995(02):2-8. 6 杨雄,姚远. TCPIP 协议及网络概述J. 成都信息工程学院学报 , 1995(01):25-34. 7 李 兴 霞 , 李 兴 家 . TCP/IP 协 议 中 IP 协 议 的 设 计 与 实 现 J. 佳 木 斯 大 学 学 报 (自 然 科 学 版 ) , 2005(02):20-28 8 赖 步 英 , 况 姗 芸 , 游 玉 椿 . 基 于 UDP 通 信 协 议 的 设 计 与 实 现 J. 河 北 理 工 学 院 学 报 , 2004(03):31-45. 9 游 玉 椿 , 赖 步 英 . 基 于 UDP 通 讯 协 议 的 设 计 J. 中 山 大 学 学 报 论 丛 , 2002(01):12-17. 10 胡建军, 杨国红. 网络通信程序设计J. 安阳师范学院学报 , 2003(02):2-19.