协议设计和架构

来源:互联网 发布:c语言数组教程 编辑:程序博客网 时间:2024/06/05 06:38

1、        IDM项目中控制报文的确认机制以及socket使用方式:

1)串行方式:

即在进行下一个业务之前,当前业务必须完成“发送-接收确认”的过程。这种方式不需要ack队列,因为当前业务未完成之前,不会开始下一个业务,所以收到的ack即是针对当前业务的。之后根据这个ack和其关联的业务进行下一步处理,比如根据ack回复的tcp端口号和业务的qos信息,建立tcp连接开始发送文件。目前IDM和IDS就是这样设计长报文的发送过程的,即IDS没有与IDM或者对端IDS完成“发送-接收”流程之前,不会开始下一个长报文业务。这样做的目的是可以单独启动一个线程去完成一个业务,使用于该业务需要消耗较长时间才能完成的情况,比如发送文件。对于这种设计,发送端可以设计成只使用一个UDPsocket来完成控制信息,且这个socket只针对这个业务有效,即业务完成后即可销毁回收。因此,这个UDPsocket应该设计为使用随机端口发送,同时使用该随机端口接收ack。

    示例:长报文控制信息的发送——接收流程即使用这个方式。即发送socket端口任意,同时使用该端口接收ack。

 

2)并行方式

即不必等待ack,即可紧接着发送下一个业务。这种方式需要一个ack队列,记录该ack是针对那个业务的。这种情况适用于完成该业务仅需较短时间即可完成,且不关注业务的先后顺序的情况。因此发送线程(或者任务)并不是只为一个业务服务的,因此这个发送用的UDPsocket应该长期存在。另外既然需要维护一个ack队列,这个维护工作一般应该由另外一个线程来进行。即

1)两个线程,一个发送线程,一个维护ack队列的线程。

那么自然就想到用两个socket,一个用来发送,一个用来接收。那么这两个socket使用的端口号应该不同。发送socket可以任意,接收ack的socket显然需要指定端口号,否则对端不知道把ack发给谁。即两个线程分别使用两个socket。

两个线程,两个socket示例:单报文控制信息的发送——接收流程。发送端发送单报文的socket端口任意,接收ack的socket端口为20074,接收端接收单报文的socket端口为20071,且用此socket发送ack。

 

当然,也可以只使用一个socket同时完成发送业务和接收ack的工作,由于发送端接收ack时需要绑定端口(因为接收端收到报文后需要知道把ack发给谁),所以发送业务之前就开始绑定了(其实这种情况下socket也可以不用绑定端口,对端采用“谁给我发,我回给谁的”的方法即可。)。这种情况下要考虑这个同时在两个线程能使用是否会有问题,比如Qt的QUdpSocekt如果要在两个线程里使用就需要考虑是否能正常工作。

两个线程共用一个socket示例:Socket_IDS中地址验证信息的发送——接收流程,发送线程(hand_timeout)和接收ack线程(hand_input)使用同一个socket,socket绑定20075。因为两个IDM或者IDS为对等,所以需要绑定端口。如果是两个不同的系统,则发送端可以不绑定。

 

2)只使用一个线程同时处理业务的发送和接收ack。

    显然,这种情况下在发送业务的同时,要时不时停下来检查使用收到了ack,效率肯定会收到影响。即一个线程使用一个socket同时负责两件事。

    示例:IDM实时流控制信息的发送——接收流程。发送socket端口和接收ack的socket为同一个,端口号为20073。

综上,一个socket需不需要绑定端口,实际上取决于对端是否知道如何和你联系。

 

2、        确认机制中的并行设计方式:

环境描述系统A、B、C,A发送请求给B,B收到后发送给C,等待C的回复,收到C的回复后将此回复转告A,或者超时未等到C的回复,将超时错误告诉A。当A是一个集合时,存在并发,情况变得复杂。处理方式:

1)为每个请求创建一个接收线程

            这种方式最简单,每个线程只负责处理特定的请求,等待针对该请求回应报文,或者超时判断。

 

2)使用一个请求队列和一个接收线程,接收线程既负责接收C的回复,又负责检查报文超时。接收回复和检查超时为串行操作。

            发送完请求报文后,将请求报文入队,由接收线程统一进行每个请求的超时判断并接收C的应答。放入队列的请求必须包含两个要素:

其一,是某个特征值。收到C的应答时可以通过这个特征值区别该应答是针对那个请求的。这个特征值可以是一个编号,或者IP等。

            其二,是绝对超时时间,通过该时间来决定如何处理该请求(是继续等待C的应答还是超时删除)。通常请求入队时按照绝对超时时间排序,方便接收线程处理。

 

3)使用定时器、一个请求队列和一个接收线程,接收线程负责接收C的回复,并决定是否取消定时。

            发送完请求报文后,为该请求启动一个定时器,由定时器的回调函数负责超时处理。而接收线程只需等待接收C的回复,收到后取消针对该请求的定时器。队列中的请求需要包含以下要素:

其一,是某个特征值。该特征值与请求绑定,这个特征值的作用:第一,收到C的应答时根据该特征值找到相对应的请求。 第二,定时器超时时,根据该特征值找到相对应的请求。

            其二,定时器编号,收到C的应答之后取消相应的定时器。

即:

接收线程通过应答中的特征值找到对应的请求,使用该请求中的定时器编号取消对应的定时器。

定时器超时回调函数,通过特征值找到相应的请求。或者定时器回调函数有输入参数的话,可以直接传入请求地址。ACE的定时器提功这种功能。由于定时器编号可能被系统回收利用,所以不推荐将定时器编号和请求绑定。

 

对于方式2)和3),当A的原始请求中包含某种信息,对该信息的处理如果依赖与C的应答的话,对于中的请求还应该包含这写信息。以便收到应答或者超时时处理。

 

3、        协议设计的一些基本原则:

在涉及到三个以上分系统时,比如A、B、C,A或者直接与B交互,或者通过B与C交互,此时应该尽可能把A的请求仅需与B交互即可完成的协议划为一类,把A的请求B接收后向C发送,且需要等待C的应答的协议划为另一类。

 

4、        模块划分的基本原则:

环境A-》B-》C之后 A《-B《-C,对于B的设计原则

B中的模块不应该即和A交互又和C交互

谁接收请求,则由谁提供针对该请求的应答的发送接口。

谁发送请求,则由谁负责接收针对该请求的应答。

中间处理模块专注于数据处理,不必考虑如何把这些数据发送出去。

交互模块专注与数据的接收和发送,不考虑如何处理数据,对于收到的数据只作简单的分类,知道要收到的数据“交给”哪个中间处理模块即可。

“交给”有两种方式:

调用中间模块的函数,即“用我的时间和别人的方法”做事

放到中间模块提供的队列中,即“用别人的时间和别人的方法”做事。

 


原创粉丝点击