在不可靠的介质上实现可靠的信息交换。考虑由数据网络连接的两个进程 a 和 b,从一个进程向另一个进程传输消息。消息发出之后,可以在任意时间内接收,也可能在网络中丢失。
网络控制过程(network control procedure,NCP)的使用增加了通信的可靠性,通过NCP,进程 a 和 b 访问网络。进程 a 给NCP A 一个信息单元 m 来初始化通信。NCP之间的交互作用(经过数据网络,DN)必须保证信息 m 被发送到进程 b(通过NCP B),之后 NCP A 通知进程 a 关于信息的发送。
即使进程 a 只传送了一个信息单元给进程 b,由于网络不稳定,NCP A 和 NCP B 之间的对话由几条消息组成,它们要维持这个对话的状态信息,但是由于每一个进程可能的对话对象数量很大, 因此在消息交换完成之后,状态信息即被抛弃。状态信息的初始化称作打开,抛弃称作关闭。
如果 a 发送消息给 b,而该信息单元未发送到 b,则称信息单元m是丢失的。
如果它被发送两次,则称单元 m 为可复制的。
可靠的通信机制不仅防止复制而且防止丢失。
可靠的通信不存在
不管 NPC 设计的如何复杂,也不可能达到完全可靠的通信。这一结论独立于数据网或者 NCP 的设计并仅仅取决于这样一个假设:NCP 可能丢失有关一次激活对话的信息。
假设进程 a 进行通信初始化之后,NCP A 与 NCP B 开始对话,再接到来自 NCP A 的消息 m 之后,假定 NCP B 将消息发送至 b。
我们尝试设计这样一种协议,在任何情况下,它都可以避免丢失。
一消息对话
1、在最简单的设计中,初始化之后,NCP A 单独由网络发送不可更改的数据,并通知 a,然后关闭。
2、NCP B 总是将所接收的数据传送给 b,传送之后即关闭。
当网络消息发送失败时,这种协议就会引起信息丢失,但是不会引入消息复制。
两消息对话
在协议中增加一个确认,就可对消息进行有限的保护以防丢失。
1、NCP A 发送 <data,m> 。
2、NCP B 接收 <data,m> ,传送 m,发送 <ack> ,关闭
3、NCP A 接收 <ack> ,通知,关闭;如果超时没有接到确认应答,重新进行步骤1
当 NCP A 超时没有收到应答,重新发送信息时,此时 NCP B 可能收到了消息,并返回了 ack,已关闭。重新收到的这个消息会被当做一个新到达的消息处理,造成了信息复制的问题。
该协议也不能保证数据不会丢失,考虑进程 a 提供两个信息单元 m1 和 m2 进行传输
1)NCP A 发送 <data,m1>
2)NCP B 接收 <data,m1> ,传送 m1,发送 <ack> ,关闭
3)NCP A 超时,发送 <data,m1> 。
4)NCP B 接收 <data,m1> , 传送 m1,发送 <ack> ,关闭
5)NCP A 接收 <ack> ,通知,关闭
6)NCP A 发送 <data,m2>
7)DN <data,m2> 丢失
8)NCP A 接收 <ack> (step 2),通知,关闭
三消息对话
1)NCP A 发送 <data,m>
2)NCP B 接收 <data,m> ,传送 m,发送 <ack>
3)NCP A 接收 <ack> ,通知,发送 <close> ,关闭
4)NCP B 接收 <close> ,关闭
如果消息 <data,m> 丢失,引起 NCP A 超时,这种情况下,NCP A 重发消息,没有问题。 <ack> 消息丢失也会引起 <data,m> 消息重发,但这不会导致复制,因为 NCP B 存在一个打开的对话,并且能够识别它已经接收的消息。
该协议仍然存在丢失和复制的可能。当 <close> 丢失时,NCP B 也必须关闭,如果没有接收到 <close> 消息,它必须重传 <ack> 消息。在 NCP B 关闭之后,NCP A 应答没有对话。重传的 <ack> 可能会到下一次 NCP A 的对话中,被当做那次对话的确认消息。
1)NCP A 发送 <data,m1>
2)NCP B 接收 <data,m1> ,传送 m1,发送 <ack>
3)NCP A 接收 <ack> ,通知,发送 <close> ,关闭
4)DN <close> 丢失
5)NCP A 发送 <data,m2>
6)DN <data,m2> 丢失
7)NCP B 重传 <ack> (第2步)
8)NCP A 接收 <ack> ,通知,发送 <close> ,关闭
9)NCP B 接收 <close> ,关闭
由于一个对话中的消息干扰了另一对话中的消息,再次引出问题。可以为每个新的对话选择一个新的对话识别号解决这个问题。NCP A,NCP B 各一个,所选的识别号包括在所有对话的信息中,用于验证所接收到的消息是否确实属于当前对话。一般的三消息协议如下:
1)NCP A 发送 <data,m,x>
2)NCP B 接收 <data,m,x> ,传送 m,发送 <ack,x,y>
3)NCP A 接收 发送 <ack,x,y> ,通知,发送 发送 <close,x,y> ,关闭
4)NCP B 接收 <close,x,y> ,关闭
该修改排除了之前给出的错误对话。
然而在传送 m 之前(第2步),NCP B 并不验证一条消息 <data,m,x> 的有效性,这很容易导致信息的复制。如果在第1步所发的消息延迟并重新发送,后到的 <data,m,x> 将引起 NCP B 再次传送消息 m。
可考虑对三消息对话做修改,使得 NCP B 在第 4 步而不是第 2 步传送数据。这样不会导致数据的重复传送,但是必须保证,NCP B 可以在任意情况下传送数据,尤其是当 <close,x,y> 消息丢失时。NCP B 重发 <ack,x,y> ,NCP A 用 <nocon,x,y> 消息应答,这引起 NCP B 传送消息和关闭。
1)NCP A 发送 <data,m,x>
2)NCP B 接收 <data,m,x> ,发送 <ack,x,y>
3)NCP A 接收 <ack,x,y> ,通知,发送 <close,x,y> ,关闭
4)DN <close,x,y> 丢失
5)NCP B 超时,重发 <ack,x,y>
6)NCP A 接收 <ack,x,y> ,应答 <nocon,x,y>
7)NCP B 接收 <nocon,x,y> ,发送 m,关闭
因此,为了避免信息丢失,即使 NCP A 不能确认与 x 和 y 有连接,NCP B 也必须发送数据,这就致使有效性机制对于 NCP B 是无效的,导致信息复制的可能性。
1)NCP A 发送 <data,m,x>
2)NCP A 超时,重发数据 <data,m,x>
3)NCP B 接收 <data,m,x> (第2步中发送),发送 <ack,x,y1>
4)NCP A 接收 <ack,x,y1> ,通知,发送 <close,x,y1> ,关闭
5)NCP B 接收 <close,x,y1> ,发送 m,关闭
6)NCP B 接收 <data,m,x> (第1步中发送),发送 <ack,x,y2>
7)NCP A 接收 <ack,x,y2> ,应答 <nocon,x,y2>
8)NCP B 接收 <nocon,x,y2> ,应答 <ack,x,y2> ,发送 m,关闭
四消息对话
如果在发送数据之前,NCP 之间认同其对话识别号,就可以避免以前对话的消息重复传送
1)NCP A 发送 <data,m,x>
2)NCP B 接收 <data,m,x> ,发送 <open,x,y>
3)NCP A 接收 <open,x,y> ,发送 <agree,x,y>
4)NCP B 接收 <agree,x,y> ,传送 m,发送 <ack,x,y> ,关闭
5)NCP A 接收 <ack,x,y> ,通知,关闭
在 NCP 损毁的情况下,仍然可能发生复制,第4步完成后,NCP B 损毁,ack 消息丢失,NCP A 重试得不到响应,必须重新发送 data,导致复制。