蔡坤琪,赵安学,邢洁清*
(1.琼台师范学院 信息科学技术学院,海南 海口 571100;2.琼台师范学院 教育大数据与人工智能研究所,海南 海口 571100)
在计算机网络中,网络主机除了要给本地用户提供服务,还要给网络的其他主机的用户提供服务。为远程计算机提供服务的进程被称为Server进程,本地计算机请求服务并发起本次进程通信的进程被称为Client进程。当客户端进程发出服务请求时,远程服务器进程会响应该客户端请求,并提供进程间通信的一种模式,被称为客户端/服务器模式。
在TCP/IP网络应用中,通信的两个进程间相互作用的主要模式是客户机/服务器模式(Client/Server),采用Client/ Server模式的理由主要有以下几点。
互联网资源分布具有不均匀性。
2.1.1 硬件
网络中主机系统类型的作用和能力等各方面差异很大。主机设备可以是某台大型的电脑高配置的服务器,也可以是一台个人电脑,甚至是一个PDA或是一个家电。
2.1.2 软件
由于所属权管理与运行环境等方面的原因,应用软件都是安装在客户端主机系统中,用户可以访问网络,注册成合法用户,然后提出和完成计算任务。
在互联网环境中,进程通信具有异步性。不同结点分布在不同网络空间,结点系统中的进程不时发出通信请求,希望和某台主机的某个进程通信。
该模式不存在统一调度与协调的高层操作系统。
Client/ Server模式的工作实质是“请求驱动”。毎次通信由Client进程随机发起。
在互联网中,Server必须要有处理并发请求的能力。在同一个时点,可能有多个Client进程向一个Server发出服务请求。
解决服务器处理并发请求的方案基本上有以下两种:一是采用并发服务器的方法;二是采用重复服务器的方法。
服务器并发的核心是服务器的守护程序(Daemon),系统启动的时候随之启动。在没有Client的服务请求到达时,并发Server处于等待状态。
当客户端服务请求到达时,服务器端根据客户端的服务请求的进程激活相应的子进程,该子进程为客户端提供服务,服务器返回等待状态。
服务器必须具有在整个网络中众所周知的进程地址。互联网中的Client进程可以根据Server进程的熟知地址,向Server提出服务请求。在实现进程通信的过程中,Client与 Server进程分别形成自己的半相关的三元组,然后Client根据Server进程的熟知进程地址建立相关的五元组。
重复服务器通过设置请求队列来存储客户端的服务请求。服务器采用先到先得的原则,依次处理客户的服务请求。
并发 Server适应于面向连接的服务类型,而重复 Server适应于无连接的服务类型。
BSD UNIX更直观地解释网络环境中进程通信的实现方法。
3.2.1 socket的基本概念
套接字是中间件抽象层,用于在应用程序层和TCP/IP协议套件之间的通信。它是一组接口。socket将复杂的TCP/IP协议系列隐藏在socket接口后面。用户拥有了一套简单的接口,从而使socket可以组织数据,遵守指定的协议。
3.2.2 套接字通信机制
套接字允许位于不同计算机上的互联进程执行通信功能。使用套接字可在特定计算机上标记和定位特定进程的地址,以便可以将数据准确地传输到目标进程。套接字包含3个参数:通信目标IP地址、传输层协议(TCP或UDP)和端口号。IP地址用于标识目标计算机,端口号用于标识目标计算机上的特定进程。套接字之间的连接分为3个阶段:监视服务器、请求客户端和确认连接[2]。
对于UNIX系统,socket调用是网络的输入/输出。
3.3.1 创建socket—socket()
应用程序在使用socket之前必须首先拥有一个socket号。这就相当于用户在安装电话时首先要向电话局申请一个电话号码。
socket()向应用程序提供创建socket的手段,socket()调用的格式是:
Socketid=socket (af, type, protocol)
返回的Socketid值是一个整数,申请一个属于自己此次进程通信的socket号,创建socket,实际上是申请1个属于自己此次进程通信的socket号,socket()一共有以下3个参数:①地址族(address family af);②类型type;③协议protocol。它们分别代表socket使用的地址类型,创建socket的应用程序所希望的通信服务类型以及socket请求使用的协议。
3.3.2 指定本地地址—bind()
创建socket()并且调用,是完成socket通信创建的第一步。它仅在相关的五元组中指定协议,并且bind()系统调用会给出本地地址和本地端口。
bind()系统调用的格式是:bind(socketid,localaddr,addr elen)
其中,Socketid是本地的socket号;localaddr是本地地址,在TCP/IP族中它就是本地主机的IP地址;addrelen对应于IP地址长度。
3.3.3 建立套接字连接connect()和accept()
accept()和connect()调用终止两个关联的连接。其中,connect()用于建立连接。连接在这里有两种含义,一种是在两个socket之间进行通信,另一种是在传输层建立连接。例如,TCP的connect()连接调用主要用于面向连接的传输服务,而accept()调用用于面向连接的传输服务。无连接socket进程可以调用connect()。但是,此时本地系统和远程系统之间没有真正的连接,它实际上通知操作系统,它将指定的套接字数据发送到此套接字。
3.3.4 接收socket连接—listen()
listen()调用是用于面向连接Server,它表示同意接受连接。
listen()调用格式是:listen(socketid,quelen)
其中,Socketid是本地socket号,表示Server可以在此socket号上接受服务请求,quelen表示请求的队列长度。
3.3.5 发送数据write()writev()与send()sendto()sendmsg()
用于面向连接传输write()writev()send()调用的格式比较一致,例如:
缓冲发送:write(socketid,buffbuffon)
集中发送:writev(socketid,iovecor,vectorlen)
可控缓冲发送:send(socketid,buff,buffer,flags)
3.3.6 接收数据read()readv()与recvfrom()recvmsg()
接收数据调用read()ready()与recvfrom()recvmsg()和发送数据调用是对应的。不同之处在于,发送数据调用的Buff是指针,而接收数据调用中的Buff是实际读出的值。
Client/Server模式直至今天仍然有其自身的优势,这种应用程序体系结构仍将长期存在。学习和了解这种模式,有助于人们理解Client/Server模式,对基于这种模式的应用程序开发和服务的搭建都很有益处。