TCPIP应用程序的通信连接模式.docx
《TCPIP应用程序的通信连接模式.docx》由会员分享,可在线阅读,更多相关《TCPIP应用程序的通信连接模式.docx(20页珍藏版)》请在冰豆网上搜索。
TCPIP应用程序的通信连接模式
TCP/IP应用程序的通信连接模式
2008年7月10日
本文的作者通过分析TCP/IP程序在不同级别上采用的不同方式来向您讲述了如何设计好TCP/IP应用程序的通信模式以及需要注意的相关问题。
TCP/IP应用层与应用程序
TCP/IP起源于二十世纪60年代末美国政府资助的一个分组交换网络研究项目,它是一个真正的开放协议,很多不同厂家生产各种型号的计算机,它们运行完全不同的操作系统,但TCP/IP协议组件允许它们互相进行通信。
现在TCP/IP已经从一个只供一些科学家使用的小实验网成长为一个由成千上万的计算机和用户构成的全球化网络,TCP/IP也已成为全球因特网(Internet)的基础,越来越多的TCP/IP互联网应用和企业商业应用正在改变着世界。
TCP/IP通讯协议采用了四层的层级模型结构(注:
这与OSI七层模型不相同),每一层都调用它的下一层所提供的网络任务来完成自己的需求。
TCP/IP的每一层都是由一系列协议来定义的。
这4层分别为:
应用层(Application):
应用层是个很广泛的概念,有一些基本相同的系统级TCP/IP应用以及应用协议,也有许多的企业商业应用和互联网应用。
传输层(Transport):
传输层包括UDP和TCP,UDP几乎不对报文进行检查,而TCP提供传输保证。
网络层(Network):
网络层协议由一系列协议组成,包括ICMP、IGMP、RIP、OSPF、IP(v4,v6)等。
链路层(Link):
又称为物理数据网络接口层,负责报文传输。
图1显示了TCP/IP层级模型结构,应用层之间的协议通过逐级调用传输层(Transportlayer)、网络层(NetworkLayer)和物理数据链路层(PhysicalDataLink)而可以实现应用层的应用程序通信互联。
应用层需要关心应用程序的逻辑细节,而不是数据在网络中的传输活动。
应用层其下三层则处理真正的通信细节。
在Internet整个发展过程中的所有思想和着重点都以一种称为RFC(RequestForComments)的文档格式存在。
针对每一种特定的TCP/IP应用,有相应的RFC文档。
一些典型的TCP/IP应用有FTP、Telnet、SMTP、SNTP、REXEC、TFTP、LPD、SNMP、NFS、INETD等。
RFC使一些基本相同的TCP/IP应用程序实现了标准化,从而使得不同厂家开发的应用程序可以互相通信。
图1TCP/IP层级模型结构
然而除了这些已经实现标准化的系统级TCP/IP应用程序外,在企业商业应用和互联网应用开发中,存在着大量的商业应用程序通信互联问题。
如图1显示,其中的应用层所包含应用程序主要可以分成两类,即系统级应用和商业应用,互联网商业应用是商业应用中的主要形式之一。
不同开发商和用户在开发各自商业应用通信程序时也存在有许多不同的设计方式。
关于TCP/IP应用层以下的技术文献与书籍早已是汗牛充栋,但是关于TCP/IP应用本身,尤其是关于商业应用的通信设计模式技术讨论方面的文章还是比较少的。
TCP/IP应用通信设计模式实际上是在TCP/IP基础编程之上的一种应用编程设计方式,也属于一种应用层协议范畴,其可以包含有TCP/IP地址族模式设计、I/O模式设计、通信连接模式设计以及通信数据格式设计等。
鉴于目前讨论TCP/IP商业应用程序设计模式问题这方面的文章还很少见,本文尝试给出一些通信连接模式设计中共同的概念与一些典型的设计模式,在以后的文章中将继续讨论地址族模式设计、I/O模式设计、以及通信数据格式设计等方面的模式设计实现话题。
通信连接模式设计主要考虑内容有:
通信两端程序建立通信方式
通信连接方式
通信报文发送与接收方式
以下内容将介绍建立通信的Client/Server模型,然后逐一介绍通信连接模式设计所需要考虑的这些内容。
回页首
传输层接口APIs与TCP/IP应用程序C/S模型
传输层接口APIs
TCP/IP应用层位于传输层之上,TCP/IP应用程序需要调用传输层的接口才能实现应用程序之间通信。
目前使用最广泛的传输层的应用编程接口是套接字接口(Socket)。
SocketAPIs是于1983年在BerkeleySocketDistribution(BSD)Unix中引进的。
1986年AT&T公司引进了另一种不同的网络层编程接口TLI(TransportLayerInterface),1988年AT&T发布了一种修改版的TLI,叫做XTI(X/openTransportinterface)。
XTI/TLI和Socket是用来处理相同任务的不同方法。
关于TCP/IPAPIs使用文章与书籍已相当多,本文则是侧重于如何组合使用这些APIs来进行TCP/IP应用程序连接模式设计,并归纳出几种基本应用连接模式。
如图2显示,应用层是通过调用传输层接口APIs(Socket或XTI/TLI)来与传输层和网络层进行通信的。
图2传输层接口
不管是使用何种编程接口,要在两个机器或两个程序之间建立通信,通信双方必须建立互相一致的通信模式。
如果双方的通信设计模式不一致就无法建立有效的通信连接。
以下是经常使用的socketAPIs,是建立TCP/IP应用程序的标准接口,也是影响TCP/IP应用程序通信方式的几个主要APIs,不同APIs组合再结合系统调用可以实现不同方式的应用。
Sockets支持多种传输层和网络层协议,支持面向连接和无连接的数据传输,允许应用分布式工作。
socket():
是用来创建一个socket,socket表示通信中的一个节点,其可以在一个网络中被命名,用socket描述符表示,socket描述符类似于Unix中的文件描述符。
bind():
是用来把本地IP层地址和TCP层端口赋予socket。
listen():
把未连接的socket转化成一个等待可连接的socket,允许该socket可以被请求连接,并指定该socket允许的最大连接数。
accept():
是等待一个连接的进入,连接成功后,产生一个新的socket描述符,这个新的描述符用来建立与客户端的连接。
connect():
用来建立一个与服务端的连接。
send():
发送一个数据缓冲区,类似Unix的文件函数write()。
另外sendto()是用在无连接的UDP程序中,用来发送自带寻址信息的数据包。
recv():
接收一个数据缓冲区,类似Unix的文件函数readI()。
另外recvfrom()是用在无连接的UDP程序中,用来接收自带寻址信息的数据包。
close():
关闭一个连接
Client/Server模型
Sockets是以Client和Server交互通信方式来使用的。
典型的系统配置是把Server放在一台机器中,而把Client放在另一台机器中,Client连接到Server交换信息。
一个socket有一系列典型的事件流。
例如,在面向连接的Client/Server模型中,Server端的socket总是等待一个Client端的请求。
要实现这个请求,Server端首先需要建立能够被Client使用的地址,当地址建立后,Server等待Client请求服务。
当一个Client通过socket连接到Server后,Client与Server之间就可以进行信息交换。
Client/Server是通信程序设计的基本模式。
从软件开发的角度讲,TCP/IP应用程序都是基于Client/Server方式的。
注意本篇文章以下Client/Server概念是针对程序内部调用SocketAPI所讲的概念,与针对整个程序甚至针对机器而讲的客户端/服务器概念有所不同。
用ServerAPIs建立的程序可以被当作客户端使用,用ClientAPIs建立的程序也可以被用作服务器端使用。
建立Server需要的APIs有socket(),bind(),listen(),accept(),建立Client需要的APIs有Socket(),Connect()。
在实际应用开发中,同一个程序里往往同时可以有Client和Server的代码,或者多种形式的组合。
在实际应用编程中,针对SocketAPIs不同有效组合,结合系统调用可以有多种复杂的设计变化。
面向连接的应用编程存在三类基本的不同级别的设计方式范畴,根据SocketAPIs从上到下顺序依次是:
Client/Server通信建立方式
Client/Server通信连接方式
Client/Server通信发送与接收方式
下面内容以面向连接的Socket应用编程为例来说明这几种不同通信范畴的设计实现。
回页首
Client/Server建立方式设计概述
一个Client连接一个Server
如果只有两台机器之间连接,那么一个是Client,另一个是Server,如下面图3所示。
这是最简单的TCP/IP的应用,也是TCP/IP应用早期的PeertoPeer(P2P)概念。
其流程基本如图4所示。
图3TCP/IP应用单点Client/Server
图4显示了TCP/IP应用编程最基本的Client/Server模式,显示了基本的Client/Server通信所需要调用的SocketAPIs以及顺序。
图4TCP/IP应用编程基本Client/Server模式
多个Client连接一个Server
多个Client同时连接一个Server是TCP/IP应用的主流形式,如图5所示,其中Client连接数可以从几个到成千上万。
图5TCP/IP应用多Client端的Client/Server
由于socketAPIs缺省方式下都是阻塞方式的,实现多个Client同时连接一个Server就需要特别的设计。
其实现方式可以有多种不同的设计,这其中也涉及I/O模式设计。
下面将展开介绍其中几种设计形式。
利用一个Client连接一个Server形式实现多Client连接
从程序设计角度讲,只要Client和Server端口是一对一形式,那么就属于一个Client连接一个Server形式。
在处理多个Client端连接时,Server端轮流使用多个端口建立多个Client-Server连接,连接关闭后,被释放端口可以被循环使用。
在这种多连接形式中需要谨慎处理Client端如何获取使用Server端的可用端口。
比如图6显示Server有一个服务于所有进程的进程可以先把Server端的可用端口发送给Client端,Client端再使用该端口建立连接来处理业务。
Server针对每一个Client连接用一个专门的进程来处理。
由于可用端口数有限,Server用一个有限循环来处理每一个可用的端口连接。
由于新端口需要用bind()来绑定,所以需要从bind()开始到close()结束都需要包含在循环体内。
图6利用一对一Client-Server模式实现多Client连接
使用多个accept()实现多Client连接
多进程Server一般有一个专注进程是服务于每一个连接的。
当Client端完成连接后,专注进程可以循环被另外的连接使用。
使用多个accept()也可以实现处理多Client连接。
多accept()的Server也只有一个socket(),一个bind(),一个listen(),这与通常情况一样。
但是它建立许多工作子进程,每一个工作子进程都有accept(),这样可以为每一个Client建立socket描述符。
如图7所示,由于accept()连接成功后,会产生一个新的socket描述符,这样通过循环多进程利用accept()产生的多socket描述符就可以与多个Client进行连接通信。
循环体是从accept()开始到close()结束的。
图7使用多accept()实现多Client连接
使用并发Server模式实现多Client连接
并发服务器模式曾经是TCP/IP的主流应用程序设计模式,得到广泛使用,目前互联网上仍有相当多的应用使用此种模式。
其设计思路是在accept之后fork出一个子进程。
因为socket会产生监听socket描述符listenfd,accept会产生连接socket描述符connfd。
连接建立后,子进程继承连接描述符服务于Client,父进程则继续使用监听描述符等待另外一个Client的连接请求,以产生另外一个连接socket描述符和子进程。
如图8所示,accept()接收到一个Client连接后,产生一个新的socket描述符,通过fork()系统调用,用一个子进程来处理该socket描述符的连接服务。
而父进程可以立即返回到accept(),等待一个新的Client请求,这就是典型的并发服务器模式。
并发服务器模式同时处理的最大并发Client连接数由listen()的第二个参数来指定。
图8TCP/IP应用并发Server
使用I/O多路技术实现多Client连接
以上三种连接设计,多Server端口、多accept()和并发服务器模式,都是通过fork()系统调用产生多进程来实现多Client连接的。
使用I/O多路技术也可以同时处理多个输入与输出问题,即用一个进程同时处理多个文件描述符。
I/O多路技术是通过select()或poll()系统调用实现的。
poll()与select()功能完全相同,但是poll()可以更少使用内存资源以及有更少的错误发生。
select()调用需要与操作文件描述符集的APIs配合使用。
select()系统调用可以使一个进程检测多个等待的I/O是否准备好,当没有设备准备好时,select()处于阻塞状态中,其中任一设备准备好后,select()函数返回调用。
select()API本身也有一个超时时间参数,超时时间到后,无论是否有设备准备好,都返回调用。
其流程如图9所示。
在socketAPIslisten()和accept()之间插入select()调用。
使用这三个宏FD_ZERO()、FD_CLR()和FD_SET(),在调用select()前设置socket描述符屏蔽位,在调用select()后使用FD_ISSET来检测socket描述符集中对应于socket描述符的位是否被设置。
FD_ISSET()就相当通知了一个socket描述符是否可以被使用,如果该socket描述符可用,则可对该socket描述符进行读写通信操作。
通常,操作系统通过宏FD_SETSIZE来声明在一个进程中select()所能操作的文件或socket描述符的最大数目。
更详细的I/O多路技术实现,可以参考其他相关文献。
图9I/O多路技术实现多连接的Server
一个Client连接多个Server
一个Client连接多个Server这种方式很少见,主要用于一个客户需要向多个服务器发送请求情况,比如一个Client端扫描连接多个Server端情况。
如图10所示。
此种方式设计主要是Client端应用程序的逻辑设计,通常需要在Client端设计逻辑循环来连接多个Server,在此不做更多描述。
图10单Client对多Server
复杂Client/Server设计与现代P2P
最近几年,对等网络技术(Peer-to-Peer,简称P2P)迅速成为计算机界关注的热门话题之一,以及影响Internet未来的科技之一。
与早期点对点(PeertoPeer)的Client/Server模式不同,现在的P2P模式是指每个结点既可充当服务器,为其他结点提供服务,同时也可作为客户端享用其他结点提供的服务。
实际上P2P模式仍然是基于Client/Server模式的,每个通信节点都既是Server,又是Client,P2P是基于复杂Client/Server设计的TCP/IP应用。
图11显示P2P模式下两个用户PC之间的对等连接。
图11P2P模式
在技术上,P2P本身是基于TCP/IPClient/Server技术的一种设计模式思想,P2P也属于网络应用层技术,与Web和FTP等应用是并列的。
只是P2P应用在设计实现上更要复杂的多。
P2P技术实现的协同工作是无需专门的服务器支持的(Serverless),这里的服务器概念与Client/Server中的Server概念是不一样的。
在传统意义上中心服务器机器上往往运行的是TCP/IP应用的Server端程序,所以传统意义上的Server概念在机器与应用上是重合的。
如果更改TCP/IP的应用设计,使应用程序既可做Server又可做Client,就可以实现无中心服务器的P2P模式。
在设计模式上,P2P模式实现了网络终端用户不依赖中心服务器或者服务商而直接进行信息和数据交换的可能,因此P2P正在改变着整个互联网的一些基础应用,从而极大地增加了用户之间的信息沟通和交流能力。
目前互联网的P2P应用与网络都正在飞速发展,一些典型的P2P应用程序比如有BitTorrent,eDonkey等,另外一些即时通信(IM)类软件比如MSN、QQ等也正在向无中心服务器模式转变。
无中心服务器的Internet应用程序大大降低应用提供商的运营成本,而且减少人们对于Server稳定性的依赖。
回页首
Client/Server通信连接方式设计
Client/Server通信方式建立后,下一步就需要考虑通信连接的方式,主要有两种方式的连接,即长连接通信与短连接通信。
通信连接方式涉及到的APIs主要是connect()和accept()。
要实现某种Client/Server方式,就必须考虑用某种特定的连接方式。
短连接通信
短连接通信是指Client方与Server方每进行一次通信报文收发交易时才进行通讯连接,交易完毕后立即断开连接。
此种方式常用于多个Client连接一个Server情况,常用于机构与用户之间通信,比如OLTP(联机事务处理)类应用。
在短连接情况下,Client端完成任务后,就关闭连接并退出。
在Server端,可以通过循环accept(),使Server不会退出,并连续处理Client的请求。
图12显示了一般情况下短连接通信模式的Socket事件流,不同设计的连接多Client的Server有不同的循环流程。
图12短连接模式通信
长连接通信
长连接通信是指Client方与Server方先建立通讯连接,连接建立后不会断开,然后再进行报文发送和接收,报文发送与接收完毕后,原来连接不会断开而继续存在,因此可以连续进行交易报文的发送与接收。
这种方式下由于通讯连接一直存在,其TCP/IP状态是Established,可以用操作系统的命令netstat查看连接是否建立。
由于在长连接情况下,Client端和Server端一样可以固定使用一个端口,所以长连接下的Client也需要使用bind()来绑定Client的端口。
在长连接方式下,需要循环读写通信数据。
为了区分每一次交易的通信数据,每一次交易数据常常需要在数据头部指定该次交易的长度,接收API需要首先读出该长度,然后再按该长度读出指定长度的字节。
长连接方式常用于一个Client端对一个Server端的通讯,一般常用于机构与机构之间的商业应用通信,以处理机构之间连续的大量的信息数据交换。
或者说可用于两个系统之间持续的信息交流情况。
通常为了加快两个系统之间的信息交流,通常还需要建立几条长连接的并行通信线路。
图13显示了一般情况下长连接通信模式的socket事件流,可见其最大特点是Client和Server都有循环体,而且循环体只包含读写APIs。
图13长连接模式通信
回页首
Client/Server通信发送与接收方式设计
在通信数据发送与接收之间也存在不同的方式,即同步和异步两种方式。
这里的同步和异步与I/O层次的同异步概念不同。
主要涉及socketAPIsrecv()和send()的不同组合方式。
同步发送与接收
从应用程序设计的角度讲,报文发送和接收是同步进行的,既报文发送后,发送方等待接收方返回消息报文。
同步方式一般需要考虑超时问题,即报文发出去后发送方不能无限等待,需要设定超时时间,超过该时间后发送方不再处于等待状态中,而直接被通知超时返回。
同步发送与接收经常与短连接通信方式结合使用,称为同步短连接通信方式,其socket事件流程可如上面的图12所示。
异步发送与接收
从应用程序设计的角度讲,发送方只管发送数据,不需要等待接收任何返回数据,而接收方只管接收数据,这就是应用层的异步发送与接收方式。
要实现异步方式,通常情况下报文发送和接收是用两个不同的进程来分别处理的,即发送与接收是分开的,相互独立的,互不影响。
异步发送与接收经常与长连接通信方式结合使用,称为异步长连接通信方式。
从应用逻辑角度讲,这种方式又可分双工和单工两种情况。
异步双工
异步双工是指应用通信的接收和发送在同一个程序中,而有两个不同的子进程分别负责发送和接收,异步双工模式是比较复杂的一种通信方式,有时候经常会出现在不同机构之间的两套系统之间的通信。
比如银行与银行之间的信息交流。
它也可以适用在现代P2P程序中。
如图14所示,Server和Client端分别fork出两个子进程,形成两对子进程之间的连接,两个连接都是单向的,一个连接是用于发送,另一个连接用于接收,这样方式的连接就被称为异步双工方式连接。
图14长连接异步双工模式
异步单工
应用通信的接收和发送是用两个不同的程序来完成,这种异步是利用两对不同程序依靠应用逻辑来实现的。
图15显示了长连接方式下的异步单工模式,在通信的A和B端,分别有两套Server和Client程序,B端的Client连接A端的Server,A端的Server只负责接收B端Client发送的报文。
A