操作系统--进程(六)

4.6 客户机–服务器系统通信

假设一个用户需要访问位于某个服务器上的数据。例如,一个用户需要知道位于服务器A上的一个文件的行、字和字符的总数。这种请示由远程服务器A处理, 它访问文件,计算所需结果,最后将真实数据传给用户。

4.6.1 套接字

套接字(socket)可定义为通信的端点。一对通过网络通信的进程需要使用一对套接字, 即每个进程各有一个。套接字由IP地址和端口号连接组成。通常, 套接字采用客户机-服务器结构。服务器通过监听制定端口来等待进来的客户机请求。一旦受到请求,服务器就接受来自客户机套接字的连接,从而完成连接。

服务器实现的特定服务(如 telnet、ftp和http)是通过监听熟知端口(telnet服务器监听端口23, ftp服务器 监听端口21, Web或 http服务器监听端口80)进行的。所有低于 1024的端口 都认为是众所周知的,可以用它们来实现标准服务。

当客户机进程发出连接请求时,它被主机赋予一个端口。该端口是大于 1024的某个任意数。 例如,如果IP地址为14.85.5.20的主机X的客户机希望与地址为 161.25.19.8的网络服务器(监听端口80)建立连接,主机X可能被赋予端口1625。该连接有一对套接字组成: 主机X上的(146.86.5.20:1625),网络服务器上的(161.25.19.8:80)。这种情况如果4.9所示。根据目的端口号,在主机间传输的数据包可分送给合适的进程。
在这里插入图片描述
图4.9 使用套接字通信
所有连接必须唯一。因此,如果主机X的另一个进程希望与同样的网络服务器建立另一个连接,那么它会被赋予另一个大于1024但不等于1625的端口号。这确保了所有连接都有唯一的一对套接字。

Java提供了三种不同类型的套接字。 面向连接(TCP) 套接字 是用Socket 类实现的。 无连接(UDP)套接字 使用了DatagramSocket类。第三种类型是 MulticastSocket类, 它是Datagramsocket类的子类。多点传送套接字允许数据发送给多个接受者。
作为基于 Java套接字的例子, 现介绍一个Java类, 它实现了 日期时间服务器。 该操作允许客户程序向服务器询问日期、时间。 服务器监听端口5155 ,不过任何大于1024 的端口都可以。 当收到连接时, 服务器会返回日期时间给客户程序。
时间服务器程序如下代码所示, 服务器创建了 ServerSocket以指明它将监听端口号 5155. 接着,它通过执行accept方法开始监听端口。服务器阻塞在方法accept上,以等待客户机请求连接。当接收到连接请求时, accept会返回一个套接字,以供服务器用来与客户机进行通信:

import java.net .*;
import java.io.*;
import class Server
{
	public static void main(String[] args) throws IOException{
		Socket client = null;
		PrintWriter pout = null;
		ServerSocket sock = null;
		try{
			sock = new ServerSocket(5155);
			//now listen for connections
			while (true){
			client = socket.accept();
			//we have a connection
			pout = new PrintWriter(client.getOutputStream(), true);
			//write the Date to the socket
			pout.println(new java.util.Date().toString());
			pout.close();
			client.close();
			}
			catch(IOException ioe){
				System.err.println(ioe);
			}
			finally{
				if(client != null)
					client.close();
				if(sock != null)
					sock.close();
			}
		}
	}
}
					日期-时间服务器

有关服务器如何与套接字通信的细节如下。首先服务器简历PrintWriter对象用来与客户机进行通信。PrintWriter对象允许服务器通过普通的输出方法print和println 来想套接字进行写操作。服务器进程通过调用方法println 将日期-时间发送给客户机。一旦完成了将 日期-时间写到套接字,服务器就关闭与客户机相连的套接字,并重新监听其他更多的请求。

客户机创建套接字跟服务器监听的端口连接,以便跟服务器进行通信,如下代码所示的Java程序 实现了客户机程序。客户机创建了 Socket,并请求与IP地址为 127.0.01、端口号为5155的服务器简历连接。一旦建立了连接,客户机就通过普通流I/O语句来对套接字金信通读。在得到服务器的日期-时间后, 就关闭端口并退出。 IP地址127.0.0.1 是特殊IP地址,称为本地主机地址。 当计算机引用地址 127.0.0.1时, 他是在引用自己。这一机制允许同一主机上的客户机和服务器能通过 TCP/IP协议进行通信。IP地址 127.0.0.1 可以为运行日期-时间服务器的另一个主机的IP地址所替代。

import java.net.*;
import java.io.*;
public class Client
{
	public static void main(String[] args) throws IOException{
		InputStream in = null;
		BufferedReader bin = null;
		Sockert sock = null;
		try
		{
			//make connection to socket
			sock = new Socket("127.0.0.1", 5155);
			in = sock.getInputStream();
			bin = new BufferedReader(new InputStreamReader(in));
			String line;
			while((line = bin.readLine()) != null)
				System.out.println(line);
		}
		catch(IOException ioe){
			System.err.println(ioe);
		}
		finally{
			if(sock != null)
				sock.close();
		}
	}
}
				**图4.11  客户端**

使用套接字通信,虽然普遍和高效,但是它属于较为低层形式的分布式进程通信。一个理由是套接字只允许在线程之间交换无结构的字节流。客户机或服务器程序需要负责加上数据的结构。在下面会介绍,可选择的两种高层的通信方法:
远程过程调用(RPC)和远程方法调用(RMI)

4.6.2 远程过程调用

一种最为普遍的远程服务形式是RPC方式,这已简单介绍过。 RPC设计成抽象过程调用机制,用于通过网络进行连接的系统。 它在许多方面类似于4.5 节所述的IPC机制,并且 通过建立在这种系统上。因为在所处理的环境中,进程在不同系统上执行。所以必须使用基于消息的通信方案来提供远程服务。 与IPC工具不同, 用于RPC通信而交换的信息有很好的结构,因此不再仅仅是数据包。这些消息传递给远程系统监听端口的RPC后台,它们包含要执行函数的名称和传递给该函数的参数。然后改函数根据请求而执行,任何输出结果通过另一个消息送回给请求者。
端口只是一个数字,它包含在消息报的开始处。虽然一个系统通常只有一个网络地址,但是它在这一地址内可以有许多端口号,以区分其所支持的许多网络服务。 如果一个远程需要服务,那么它就像适当端口发送它的消息。例如,如果一个系统欲允许其他系统能列出其当前用户,那么它可以有一个后天支持这样的RPC,并监听一个端口如3027。任何远程系统只要向位于服务器端口3027发送一个RPC消息,就能得到所有需要的信息(即当前用户列表),数据将通过答复消息接收。
RPC语义允许客户机调用位于远程主机上的过程,就如同调用本地过程一样。 RPC 系统隐藏了必要细节,以允许通信发生。 RPC系统通过在客户机段 提供存根(stub)来做到这一点。通常, 对于每个独立的远程过程都有一个不同的存根。当客户机调用远程过程时,RPC系统调用合适的存根,并传递提供远程过程的参数。该存根定位服务器的端口,并编组参数。 参数编组涉及到将参数打包成可通过网络传输的形式。接着,存根使用消息传递向服务器发送一个消息。服务器端的一个类似存根接收到这一消息,并调用服务器上的过程。如果有必要,返回值可通过使用同样的技术,以传回给客户机。
有一个必须处理的事项是关于如何处理客户机和服务器系统机的数据表示的差别。考虑一个32bit整数的表示。有的系统使用高内存地址来存储最重要的字节(称为大端结尾big-endian),而其他系统使用高内存地址来存储最大重要的字节(称为小端结尾little-endian)。为了处理这一问题。许多RPC系统都定义了数据的机器无关表示。一种这样的表示称为外部数据表示(XDR)。 在客户机端,参数编辑组涉及到将机器相关数据编组成XDR来向服务器发送消息。在服务器端,XDR数据被解除编组,并重新转换成服务器所用的机器相关表示。

RPC机制在许多网络系统中应用普遍,所以应讨论有关其操作等一些其他事项。其中, 重要的一个问题就是调用的语义。 虽然本地过程调用只有在极端情况下才失败,但是RPC由于普通网络错误,可能会失败,或被重复和多次执行。因为人们是通过不可靠的通信线路来传输消息,所以操作系统较容易确保一个消息最多只执行一次,而不是刚好执行一次。因为 本地过程调用 具有最后的属性,所以绝大多数系统试图也拥有这一功能。它们通过为每个消息附加时间戳的方法来做到。服务器对其所处理的消息,必须有一个完整的或足够长的时间戳历史,以便确保能检测到重复消息。进来的消息,如果其时间戳已在历史上,则被忽略。如果产生这些时间戳会在后面讨论。
另一个重要事项是关于服务器与客户机间的通信。对于标准过程调用,在连接、装入或执行时会出现一定形式的捆绑,如过程调用名称 被过程调用的内存地址所代替。 RPC方案要求有一个类似的用户客户机和服务器端口的捆绑,但是客户机如何知道服务器上的端口呢?没有一个系统拥有其他系统安全的信息,因为他们并不共享内存。有两种常用的方法。
第一种方法, 捆绑信息以固定端口地址形式预先固定。 在编译时,RPC调用有一个相关的固定端口号。 一旦程序被编译后,服务器就不能改变请求服务端端口号。第二种方法,捆绑通过集合点机制动态进行。通常,操作系统在一个固定RPC端口上提供集合后台程序(也称为 matchmaker)。 客户程序发送一个消息(包括RPC的名称)给集合服务程序,以请求它所需要执行的RPC端口地址。该端口号返回, RPC调用可发送至这一端口直到进程终止(或服务器失败)。这种方法需要初始请求的额外开销,但是比第一种方法更灵活。图4.12 说明了一个交互例子。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值