Internet Engineering Task Force (IETF)                     M. Thornburgh
Request for Comments: 7016                                         Adobe
Category: Informational                                    November 2013
ISSN: 2070-1721
        
Internet Engineering Task Force (IETF)                     M. Thornburgh
Request for Comments: 7016                                         Adobe
Category: Informational                                    November 2013
ISSN: 2070-1721
        

Adobe's Secure Real-Time Media Flow Protocol

Adobe的安全实时媒体流协议

Abstract

摘要

This memo describes Adobe's Secure Real-Time Media Flow Protocol (RTMFP), an endpoint-to-endpoint communication protocol designed to securely transport parallel flows of real-time video, audio, and data messages, as well as bulk data, over IP networks. RTMFP has features that make it effective for peer-to-peer (P2P) as well as client-server communications, even when Network Address Translators (NATs) are used.

本备忘录介绍了Adobe的安全实时媒体流协议(RTMFP),这是一种端点到端点的通信协议,旨在通过IP网络安全地传输实时视频、音频和数据消息以及批量数据的并行流。RTMFP的特性使其能够有效地进行对等(P2P)和客户机-服务器通信,即使在使用网络地址转换器(NAT)时也是如此。

Status of This Memo

关于下段备忘

This document is not an Internet Standards Track specification; it is published for informational purposes.

本文件不是互联网标准跟踪规范;它是为了提供信息而发布的。

This document is a product of the Internet Engineering Task Force (IETF). It has been approved for publication by the Internet Engineering Steering Group (IESG). Not all documents approved by the IESG are a candidate for any level of Internet Standard; see Section 2 of RFC 5741.

本文件是互联网工程任务组(IETF)的产品。互联网工程指导小组(IESG)已批准将其出版。并非IESG批准的所有文件都适用于任何级别的互联网标准;见RFC 5741第2节。

Information about the current status of this document, any errata, and how to provide feedback on it may be obtained at http://www.rfc-editor.org/info/rfc7016.

有关本文件当前状态、任何勘误表以及如何提供反馈的信息,请访问http://www.rfc-editor.org/info/rfc7016.

IESG Note

IESG注释

This document represents technology developed outside the processes of the IETF and the IETF community has determined that it is useful to publish it as an RFC in its current form. It is a product of the IETF only in that it has received public review and has been approved for publication by the Internet Engineering Steering Group (IESG), but the content of the document does not represent a consensus of the IETF.

本文件代表了在IETF过程之外开发的技术,IETF社区已确定将其以当前形式发布为RFC是有用的。它是IETF的产品,只是因为它已经接受了公众审查,并且已经被互联网工程指导小组(IESG)批准出版,但文件的内容并不代表IETF的共识。

Copyright Notice

版权公告

Copyright (c) 2013 IETF Trust and the persons identified as the document authors. All rights reserved.

版权所有(c)2013 IETF信托基金和确定为文件作者的人员。版权所有。

This document is subject to BCP 78 and the IETF Trust's Legal Provisions Relating to IETF Documents (http://trustee.ietf.org/license-info) in effect on the date of publication of this document. Please review these documents carefully, as they describe your rights and restrictions with respect to this document. Code Components extracted from this document must include Simplified BSD License text as described in Section 4.e of the Trust Legal Provisions and are provided without warranty as described in the Simplified BSD License.

本文件受BCP 78和IETF信托有关IETF文件的法律规定的约束(http://trustee.ietf.org/license-info)自本文件出版之日起生效。请仔细阅读这些文件,因为它们描述了您对本文件的权利和限制。从本文件中提取的代码组件必须包括信托法律条款第4.e节中所述的简化BSD许可证文本,并提供简化BSD许可证中所述的无担保。

This document may not be modified, and derivative works of it may not be created, except to format it for publication as an RFC or to translate it into languages other than English.

不得修改本文件,也不得创建其衍生作品,除非将其格式化为RFC出版或将其翻译为英语以外的其他语言。

Table of Contents

目录

   1. Introduction ....................................................5
      1.1. Design Highlights of RTMFP .................................6
      1.2. Terminology ................................................7
   2. Syntax ..........................................................8
      2.1. Common Elements ............................................8
           2.1.1. Elementary Types and Constructs .....................8
           2.1.2. Variable Length Unsigned Integer (VLU) .............10
           2.1.3. Option .............................................10
           2.1.4. Option List ........................................11
           2.1.5. Internet Socket Address (Address) ..................12
      2.2. Network Layer .............................................13
           2.2.1. Encapsulation ......................................13
           2.2.2. Multiplex ..........................................13
           2.2.3. Encryption .........................................14
           2.2.4. Packet .............................................15
      2.3. Chunks ....................................................18
           2.3.1. Packet Fragment Chunk ..............................20
           2.3.2. Initiator Hello Chunk (IHello) .....................21
           2.3.3. Forwarded Initiator Hello Chunk (FIHello) ..........22
           2.3.4. Responder Hello Chunk (RHello) .....................23
           2.3.5. Responder Redirect Chunk (Redirect) ................24
           2.3.6. RHello Cookie Change Chunk .........................26
           2.3.7. Initiator Initial Keying Chunk (IIKeying) ..........27
           2.3.8. Responder Initial Keying Chunk (RIKeying) ..........29
           2.3.9. Ping Chunk .........................................31
           2.3.10. Ping Reply Chunk ..................................32
        
   1. Introduction ....................................................5
      1.1. Design Highlights of RTMFP .................................6
      1.2. Terminology ................................................7
   2. Syntax ..........................................................8
      2.1. Common Elements ............................................8
           2.1.1. Elementary Types and Constructs .....................8
           2.1.2. Variable Length Unsigned Integer (VLU) .............10
           2.1.3. Option .............................................10
           2.1.4. Option List ........................................11
           2.1.5. Internet Socket Address (Address) ..................12
      2.2. Network Layer .............................................13
           2.2.1. Encapsulation ......................................13
           2.2.2. Multiplex ..........................................13
           2.2.3. Encryption .........................................14
           2.2.4. Packet .............................................15
      2.3. Chunks ....................................................18
           2.3.1. Packet Fragment Chunk ..............................20
           2.3.2. Initiator Hello Chunk (IHello) .....................21
           2.3.3. Forwarded Initiator Hello Chunk (FIHello) ..........22
           2.3.4. Responder Hello Chunk (RHello) .....................23
           2.3.5. Responder Redirect Chunk (Redirect) ................24
           2.3.6. RHello Cookie Change Chunk .........................26
           2.3.7. Initiator Initial Keying Chunk (IIKeying) ..........27
           2.3.8. Responder Initial Keying Chunk (RIKeying) ..........29
           2.3.9. Ping Chunk .........................................31
           2.3.10. Ping Reply Chunk ..................................32
        
           2.3.11. User Data Chunk ...................................33
                  2.3.11.1. Options for User Data ....................35
                           2.3.11.1.1. User's Per-Flow Metadata ......35
                           2.3.11.1.2. Return Flow Association .......36
           2.3.12. Next User Data Chunk ..............................37
           2.3.13. Data Acknowledgement Bitmap Chunk (Bitmap Ack) ....39
           2.3.14. Data Acknowledgement Ranges Chunk (Range Ack) .....41
           2.3.15. Buffer Probe Chunk ................................43
           2.3.16. Flow Exception Report Chunk .......................43
           2.3.17. Session Close Request Chunk (Close) ...............44
           2.3.18. Session Close Acknowledgement Chunk (Close Ack) ...44
   3. Operation ......................................................45
      3.1. Overview ..................................................45
      3.2. Endpoint Identity .........................................46
      3.3. Packet Multiplex ..........................................48
      3.4. Packet Fragmentation ......................................48
      3.5. Sessions ..................................................50
           3.5.1. Startup ............................................53
                  3.5.1.1. Normal Handshake ..........................53
                           3.5.1.1.1. Initiator ......................54
                           3.5.1.1.2. Responder ......................55
                  3.5.1.2. Cookie Change .............................57
                  3.5.1.3. Glare .....................................59
                  3.5.1.4. Redirector ................................60
                  3.5.1.5. Forwarder .................................61
                  3.5.1.6. Redirector and Forwarder with NAT .........63
                  3.5.1.7. Load Distribution and Fault Tolerance .....66
           3.5.2. Congestion Control .................................67
                  3.5.2.1. Time Critical Reverse Notification ........68
                  3.5.2.2. Retransmission Timeout ....................68
                  3.5.2.3. Burst Avoidance ...........................71
           3.5.3. Address Mobility ...................................71
           3.5.4. Ping ...............................................72
                  3.5.4.1. Keepalive .................................72
                  3.5.4.2. Address Mobility ..........................73
                  3.5.4.3. Path MTU Discovery ........................74
           3.5.5. Close ..............................................74
      3.6. Flows .....................................................75
           3.6.1. Overview ...........................................75
                  3.6.1.1. Identity ..................................75
                  3.6.1.2. Messages and Sequencing ...................76
                  3.6.1.3. Lifetime ..................................77
        
           2.3.11. User Data Chunk ...................................33
                  2.3.11.1. Options for User Data ....................35
                           2.3.11.1.1. User's Per-Flow Metadata ......35
                           2.3.11.1.2. Return Flow Association .......36
           2.3.12. Next User Data Chunk ..............................37
           2.3.13. Data Acknowledgement Bitmap Chunk (Bitmap Ack) ....39
           2.3.14. Data Acknowledgement Ranges Chunk (Range Ack) .....41
           2.3.15. Buffer Probe Chunk ................................43
           2.3.16. Flow Exception Report Chunk .......................43
           2.3.17. Session Close Request Chunk (Close) ...............44
           2.3.18. Session Close Acknowledgement Chunk (Close Ack) ...44
   3. Operation ......................................................45
      3.1. Overview ..................................................45
      3.2. Endpoint Identity .........................................46
      3.3. Packet Multiplex ..........................................48
      3.4. Packet Fragmentation ......................................48
      3.5. Sessions ..................................................50
           3.5.1. Startup ............................................53
                  3.5.1.1. Normal Handshake ..........................53
                           3.5.1.1.1. Initiator ......................54
                           3.5.1.1.2. Responder ......................55
                  3.5.1.2. Cookie Change .............................57
                  3.5.1.3. Glare .....................................59
                  3.5.1.4. Redirector ................................60
                  3.5.1.5. Forwarder .................................61
                  3.5.1.6. Redirector and Forwarder with NAT .........63
                  3.5.1.7. Load Distribution and Fault Tolerance .....66
           3.5.2. Congestion Control .................................67
                  3.5.2.1. Time Critical Reverse Notification ........68
                  3.5.2.2. Retransmission Timeout ....................68
                  3.5.2.3. Burst Avoidance ...........................71
           3.5.3. Address Mobility ...................................71
           3.5.4. Ping ...............................................72
                  3.5.4.1. Keepalive .................................72
                  3.5.4.2. Address Mobility ..........................73
                  3.5.4.3. Path MTU Discovery ........................74
           3.5.5. Close ..............................................74
      3.6. Flows .....................................................75
           3.6.1. Overview ...........................................75
                  3.6.1.1. Identity ..................................75
                  3.6.1.2. Messages and Sequencing ...................76
                  3.6.1.3. Lifetime ..................................77
        
           3.6.2. Sender .............................................78
                  3.6.2.1. Startup ...................................80
                  3.6.2.2. Queuing Data ..............................80
                  3.6.2.3. Sending Data ..............................81
                           3.6.2.3.1. Startup Options ................83
                           3.6.2.3.2. Send Next Data .................83
                  3.6.2.4. Processing Acknowledgements ...............83
                  3.6.2.5. Negative Acknowledgement and Loss .........84
                  3.6.2.6. Timeout ...................................85
                  3.6.2.7. Abandoning Data ...........................86
                           3.6.2.7.1. Forward Sequence Number
                                      Update .........................86
                  3.6.2.8. Examples ..................................87
                  3.6.2.9. Flow Control ..............................89
                           3.6.2.9.1. Buffer Probe ...................89
                  3.6.2.10. Exception ................................89
                  3.6.2.11. Close ....................................90
           3.6.3. Receiver ...........................................90
                  3.6.3.1. Startup ...................................93
                  3.6.3.2. Receiving Data ............................94
                  3.6.3.3. Buffering and Delivering Data .............95
                  3.6.3.4. Acknowledging Data ........................97
                           3.6.3.4.1. Timing .........................98
                           3.6.3.4.2. Size and Truncation ............99
                           3.6.3.4.3. Constructing ...................99
                           3.6.3.4.4. Delayed Acknowledgement .......100
                           3.6.3.4.5. Obligatory Acknowledgement ....100
                           3.6.3.4.6. Opportunistic
                                      Acknowledgement ...............100
                           3.6.3.4.7. Example .......................101
                  3.6.3.5. Flow Control .............................102
                  3.6.3.6. Receiving a Buffer Probe .................103
                  3.6.3.7. Rejecting a Flow .........................103
                  3.6.3.8. Close ....................................104
   4. IANA Considerations ...........................................104
   5. Security Considerations .......................................105
   6. Acknowledgements ..............................................106
   7. References ....................................................107
      7.1. Normative References .....................................107
      7.2. Informative References ...................................107
   Appendix A. Example Congestion Control Algorithm .................108
     A.1. Discussion ................................................108
     A.2. Algorithm .................................................110
        
           3.6.2. Sender .............................................78
                  3.6.2.1. Startup ...................................80
                  3.6.2.2. Queuing Data ..............................80
                  3.6.2.3. Sending Data ..............................81
                           3.6.2.3.1. Startup Options ................83
                           3.6.2.3.2. Send Next Data .................83
                  3.6.2.4. Processing Acknowledgements ...............83
                  3.6.2.5. Negative Acknowledgement and Loss .........84
                  3.6.2.6. Timeout ...................................85
                  3.6.2.7. Abandoning Data ...........................86
                           3.6.2.7.1. Forward Sequence Number
                                      Update .........................86
                  3.6.2.8. Examples ..................................87
                  3.6.2.9. Flow Control ..............................89
                           3.6.2.9.1. Buffer Probe ...................89
                  3.6.2.10. Exception ................................89
                  3.6.2.11. Close ....................................90
           3.6.3. Receiver ...........................................90
                  3.6.3.1. Startup ...................................93
                  3.6.3.2. Receiving Data ............................94
                  3.6.3.3. Buffering and Delivering Data .............95
                  3.6.3.4. Acknowledging Data ........................97
                           3.6.3.4.1. Timing .........................98
                           3.6.3.4.2. Size and Truncation ............99
                           3.6.3.4.3. Constructing ...................99
                           3.6.3.4.4. Delayed Acknowledgement .......100
                           3.6.3.4.5. Obligatory Acknowledgement ....100
                           3.6.3.4.6. Opportunistic
                                      Acknowledgement ...............100
                           3.6.3.4.7. Example .......................101
                  3.6.3.5. Flow Control .............................102
                  3.6.3.6. Receiving a Buffer Probe .................103
                  3.6.3.7. Rejecting a Flow .........................103
                  3.6.3.8. Close ....................................104
   4. IANA Considerations ...........................................104
   5. Security Considerations .......................................105
   6. Acknowledgements ..............................................106
   7. References ....................................................107
      7.1. Normative References .....................................107
      7.2. Informative References ...................................107
   Appendix A. Example Congestion Control Algorithm .................108
     A.1. Discussion ................................................108
     A.2. Algorithm .................................................110
        
1. Introduction
1. 介绍

Adobe's Secure Real-Time Media Flow Protocol (RTMFP) is intended for use as a general purpose endpoint-to-endpoint data transport service in IP networks. It has features that make it well suited to the transport of real-time media (such as low-delay video, audio, and data) as well as bulk data, and for client-server as well as peer-to-peer (P2P) communication. These features include independent parallel message flows that may have different delivery priorities, variable message reliability (from TCP-like full reliability to UDP-like best effort), multi-point congestion control, and built-in security. Session multiplexing and facilities to support UDP hole-punching simplify Network Address Translator (NAT) traversal in peer-to-peer systems.

Adobe的安全实时媒体流协议(RTMFP)旨在用作IP网络中的通用端点到端点数据传输服务。它的特性使其非常适合于实时媒体(如低延迟视频、音频和数据)以及海量数据的传输,也适合于客户端-服务器以及对等(P2P)通信。这些功能包括独立的并行消息流,这些消息流可能具有不同的传递优先级、可变的消息可靠性(从类似TCP的完全可靠性到类似UDP的尽力而为)、多点拥塞控制和内置安全性。会话多路复用和支持UDP打孔的设施简化了对等系统中的网络地址转换器(NAT)遍历。

RTMFP is implemented in Flash Player, Adobe Integrated Runtime (AIR), and Adobe Media Server (AMS, formerly Flash Media Server or FMS), all from Adobe Systems Incorporated, and is used as the foundation transport protocol for real-time video, audio, and data communication, both client-server and P2P, in those products. At the time of writing, the Adobe Flash Player runtime is installed on more than one billion end-user desktop computers.

RTMFP是在Flash播放器、Adobe集成运行时(Air)和Adobe媒体服务器(AMS,以前的Flash媒体服务器或FMS)中实现的,全部来自Adobe Systems Systems,并被用作客户机服务器和P2P的实时视频、音频和数据通信的基础传输协议,在这些产品中。在撰写本文时,AdobeFlashPlayer运行时安装在超过10亿台终端用户桌面计算机上。

RTMFP was developed by Adobe Systems Incorporated and is not the product of an IETF activity.

RTMFP由Adobe Systems Incorporated开发,不是IETF活动的产品。

This memo describes the syntax and operation of the Secure Real-Time Media Flow Protocol.

本备忘录描述了安全实时媒体流协议的语法和操作。

This memo describes a general security framework that, when combined with an application-specific Cryptography Profile, can be used to establish a confidential and authenticated session between endpoints. The application-specific Cryptography Profile, not defined herein, would detail the specific cryptographic algorithms, data formats, and semantics to be used within this framework. Interoperation between applications of RTMFP requires common or compatible Cryptography Profiles.

本备忘录描述了一个通用安全框架,当与特定于应用程序的加密配置文件结合使用时,该框架可用于在端点之间建立一个机密且经过身份验证的会话。本文未定义的特定于应用程序的加密配置文件将详细说明在此框架内使用的特定加密算法、数据格式和语义。RTMFP应用程序之间的互操作需要通用或兼容的加密配置文件。

Note to implementers: at the time of writing, the Cryptography Profile used by the above-mentioned Adobe products is not publicly described by Adobe. Implementers should investigate the availability of documentation of that Cryptography Profile prior to implementing RTMFP for the purpose of interoperation with the above-mentioned Adobe products.

实现者注意:在撰写本文时,Adobe并未公开描述上述Adobe产品使用的加密配置文件。为了与上述Adobe产品进行互操作,实施者应在实施RTMFP之前调查该加密配置文件的文档可用性。

1.1. Design Highlights of RTMFP
1.1. RTMFP的设计要点

Between any pair of communicating endpoints is a single, bidirectional, secured, congestion controlled session. Unidirectional flows convey messages from one end to the other within the session. An endpoint can have concurrent sessions with multiple other far endpoints.

在任何一对通信端点之间是一个单一的、双向的、安全的、拥塞控制的会话。单向流在会话内将消息从一端传递到另一端。一个端点可以与多个其他远端端点具有并发会话。

Design highlights of RTMFP include the following:

RTMFP的设计亮点包括:

o The security framework is an inherent part of the basic protocol. The application designer chooses the cryptographic formats and algorithms to suit the needs of the application, and may update them as the state of the security arts progresses.

o 安全框架是基本协议的固有部分。应用程序设计者选择加密格式和算法以满足应用程序的需要,并可能随着安全技术的发展而更新它们。

o Cryptographic Endpoint Discriminators can resist port scanning.

o 加密端点鉴别器可以抵抗端口扫描。

o All header, control, and framing information, except for network addressing information and a session identifier, is encrypted according to the Cryptography Profile.

o 除网络寻址信息和会话标识符外,所有报头、控制和帧信息都根据加密配置文件进行加密。

o There is a single session and associated congestion control state between a pair of endpoints.

o 在一对端点之间存在单个会话和关联的拥塞控制状态。

o Each session may have zero or more unidirectional message-oriented flows in each direction. All of a session's sending flows share the session's congestion control state.

o 每个会话在每个方向上可能有零个或多个单向面向消息的流。会话的所有发送流共享会话的拥塞控制状态。

o Return Flow Association (Section 2.3.11.1.2) generalizes bidirectional communication to arbitrarily complex trees of flows.

o 回流关联(第2.3.11.1.2节)将双向通信概括为任意复杂的流树。

o Messages in flows can be arbitrarily large and are fragmented for transmission.

o 流中的消息可以任意大,并且为传输而分段。

o Messages of any size may be sent with full, partial, or no reliability (sender's choice). Messages may be delivered to the receiving user in original queuing order or network arrival order (receiver's choice).

o 任何大小的邮件都可以完全、部分或不可靠地发送(发件人选择)。消息可以按照原始排队顺序或网络到达顺序(接收方选择)交付给接收用户。

o Flows are named with arbitrary, user-defined metadata (Section 2.3.11.1.1) rather than port or stream numbers.

o 流使用任意的用户定义元数据(第2.3.11.1.1节)命名,而不是端口号或流号。

o The sequence numbers of each flow are independent of all other flows and are not permanently bound to a session-wide transmission ordering. This allows real-time priority decisions to be made at transmission or retransmission time.

o 每个流的序列号独立于所有其他流,并且不会永久绑定到会话范围的传输顺序。这允许在传输或重传时做出实时优先级决策。

o Each flow has its own receive window and, therefore, independent flow control.

o 每个流都有自己的接收窗口,因此具有独立的流控制。

o Round trips are expensive and are minimized or eliminated when possible.

o 往返费用昂贵,尽可能减少或消除。

o After a session is established, flows begin by sending the flow's messages with no additional handshake (and associated round trips).

o 会话建立后,流开始发送流的消息,无需额外握手(以及相关的往返)。

o Transmitting bytes on the network is much more expensive than moving bytes in a CPU or memory. Wasted bytes are minimized or eliminated when possible and practical, and variable length encodings are used, even at the expense of breaking 32-bit alignment and making the text diagrams in this specification look awkward.

o 在网络上传输字节比在CPU或内存中移动字节要昂贵得多。在可能和实际的情况下,可以最小化或消除浪费的字节,并使用可变长度编码,即使代价是破坏32位对齐,并使本规范中的文本图看起来很尴尬。

o P2P lookup and peer introduction (including UDP hole-punching for NAT and firewall traversal) are supported directly by the session startup handshake.

o 会话启动握手直接支持P2P查找和对等引入(包括NAT的UDP打孔和防火墙穿越)。

o Session identifiers allow an endpoint to multiplex many sessions over a single local transport address while allowing sessions to survive changes in transport address (as may happen in mobile or wireless deployments).

o 会话标识符允许端点在单个本地传输地址上多路传输多个会话,同时允许会话在传输地址的更改中生存(在移动或无线部署中可能会发生这种情况)。

The syntax of the protocol is detailed in Section 2. The operation of the protocol is detailed in Section 3.

第2节详细介绍了协议的语法。第3节详细介绍了协议的操作。

1.2. Terminology
1.2. 术语

The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in [RFC2119].

本文件中的关键词“必须”、“不得”、“必需”、“应”、“不应”、“建议”、“不建议”、“可”和“可选”应按照[RFC2119]中的说明进行解释。

2. Syntax
2. 语法

Definitions of types and structures in this specification use traditional text diagrams paired with procedural descriptions using a C-like syntax. The C-like procedural descriptions SHALL be construed as definitive.

本规范中的类型和结构定义使用传统的文本图,并使用类似C的语法进行过程描述。C类程序说明应解释为最终说明。

Structures are packed to take only as many bytes as explicitly indicated. There is no 32-bit alignment constraint, and fields are not padded for alignment unless explicitly indicated or described. Text diagrams may include a bit ruler across the top; this is a convenience for counting bits in individual fields and does not necessarily imply field alignment on a multiple of the ruler width.

结构被压缩为只占用显式指示的字节数。不存在32位对齐约束,除非明确指示或说明,否则不会填充字段进行对齐。文本图可能包括顶部的位尺;这便于计算单个字段中的位,并不一定意味着字段对齐为标尺宽度的倍数。

Unless specified otherwise, reserved fields SHOULD be set to 0 by a sender and MUST be ignored by a receiver.

除非另有规定,否则发送方应将保留字段设置为0,接收方必须忽略该字段。

The procedural syntax of this specification defines correct and error-free encoded inputs to a parser. The procedural syntax does not describe a fully featured parser, including error detection and handling. Implementations MUST include means to identify error circumstances, including truncations causing elementary or composed types to not fit inside containing structures, fields, or elements. Unless specified otherwise, an error circumstance SHALL abort the parsing and processing of an element and its enclosing elements, up to the containing packet.

本规范的过程语法定义了到解析器的正确且无错误的编码输入。过程语法没有描述功能齐全的解析器,包括错误检测和处理。实现必须包括识别错误情况的方法,包括导致基本类型或组合类型不适合包含结构、字段或元素的截断。除非另有规定,否则错误情况应中止元素及其封闭元素的解析和处理,直至包含数据包。

2.1. Common Elements
2.1. 共同要素

This section lists types and structures that are used throughout this specification.

本节列出了本规范中使用的类型和结构。

2.1.1. Elementary Types and Constructs
2.1.1. 基本类型和结构

This section lists the elementary types and constructs out of which all of the following sections' definitions are built.

本节列出了基本类型和构造,以下各节的定义都是基于这些类型和构造生成的。

uint8_t var;

uint8_t var;

An unsigned integer 8 bits (one byte) in length and byte aligned.

长度为8位(一个字节)且字节对齐的无符号整数。

uint16_t var;

uint16_t var;

An unsigned integer 16 bits in length, in network byte order ("big endian") and byte aligned.

长度为16位的无符号整数,按网络字节顺序(“big-endian”)和字节对齐。

uint32_t var;

uint32_t var;

An unsigned integer 32 bits in length, in network byte order and byte aligned.

长度为32位的无符号整数,按网络字节顺序和字节对齐。

uint128_t var;

uint128_t var;

An unsigned integer 128 bits in length, in network byte order and byte aligned.

长度为128位的无符号整数,按网络字节顺序和字节对齐。

uintn_t var :bitsize;

uintn\u t var:位大小;

An unsigned integer of any other size, potentially not byte aligned. Its size in bits is specified explicitly by bitsize.

任何其他大小的无符号整数,可能未对齐字节。其大小(以位为单位)由bitsize显式指定。

bool_t var :1;

bool_t var:1;

A boolean flag having the value true (1 or set) or false (0 or clear) and being one bit in length.

一种布尔标志,其值为true(1或set)或false(0或clear),长度为一位。

type var[num];

类型var[num];

A packed array of type with length num*sizeof(type)*8 bits.

长度为num*sizeof(type)*8位的压缩数组。

   struct name_t { ... } name :bitsize;
        
   struct name_t { ... } name :bitsize;
        

A packed structure. Its size in bits is specified by bitsize.

填充结构。其大小(以位为单位)由bitsize指定。

remainder();

余数();

The number of bytes from the current offset to the end of the enclosing structure.

从当前偏移量到封闭结构结尾的字节数。

type var[remainder()];

类型var[rements()];

A packed array of type, its size extending to the end of the enclosing structure.

类型的压缩数组,其大小延伸到封闭结构的末端。

Note that a bitsize of "variable" indicates that the size of the structure is determined by the sizes of its interior components. A bitsize of "n*8" indicates that the size of the structure is a whole number of bytes and is byte aligned.

请注意,“variable”的bitsize表示结构的大小由其内部构件的大小决定。位大小为“n*8”表示结构的大小是字节的整数,并且是字节对齐的。

2.1.2. Variable Length Unsigned Integer (VLU)
2.1.2. 可变长度无符号整数(VLU)

A VLU encodes any finite non-negative integer into one or more bytes. For each encoded byte, if the high bit is set, the next byte is also part of the VLU. If the high bit is clear, this is the final byte of the VLU. The remaining bits encode the number, seven bits at a time, from most significant to least significant.

VLU将任何有限的非负整数编码为一个或多个字节。对于每个编码字节,如果设置高位,则下一个字节也是VLU的一部分。如果高位清除,则这是VLU的最后一个字节。剩余的位对数字进行编码,一次七位,从最高有效到最低有效。

    0 1 2 3 4 5 6 7                 0 1 2 3 4 5 6 7
   +~+~+~+~+~+~+~+~+               +-+-+-+-+-+-+-+-+
   |1|    digit    |...............|0|    digit    |
   +~+~+~+~+~+~+~+~+               +-+-+-+-+-+-+-+-+
   ^                               ^
   +--------- zero or more --------+
        
    0 1 2 3 4 5 6 7                 0 1 2 3 4 5 6 7
   +~+~+~+~+~+~+~+~+               +-+-+-+-+-+-+-+-+
   |1|    digit    |...............|0|    digit    |
   +~+~+~+~+~+~+~+~+               +-+-+-+-+-+-+-+-+
   ^                               ^
   +--------- zero or more --------+
        
   struct vlu_t
   {
       value = 0;
       do {
           bool_t  more  :1;
           uintn_t digit :7;
           value = (value * 128) + digit;
       } while(more);
   } :variable*8;
        
   struct vlu_t
   {
       value = 0;
       do {
           bool_t  more  :1;
           uintn_t digit :7;
           value = (value * 128) + digit;
       } while(more);
   } :variable*8;
        
                              +-------------/-+
                              |             \ |
                              +-------------/-+
        
                              +-------------/-+
                              |             \ |
                              +-------------/-+
        

Figure 1: VLU Depiction in Following Diagrams

图1:下图中的VLU描述

Unless stated otherwise in this specification, implementations SHOULD handle VLUs encoding unsigned integers at least 64 bits in length (that is, encoding a maximum value of at least 2^64 - 1).

除非本规范中另有说明,否则实现应处理长度至少为64位的无符号整数的VLU编码(即,编码的最大值至少为2^64-1)。

2.1.3. Option
2.1.3. 选项

An Option is a Length-Type-Value triplet. Length and Type are encoded in VLU format. Length is the number of bytes of payload following the Length field. The payload comprises the Type and Value fields. Type identifies the kind of option this is. The syntax of the Value field is determined by the type of option.

选项是长度类型值三元组。长度和类型以VLU格式编码。Length是长度字段后面的有效负载字节数。有效负载包括类型和值字段。类型标识此选项的类型。值字段的语法由选项的类型决定。

An Option can have a length of zero, in which case it has no type and no value and is empty. An empty Option is called a "Marker".

选项的长度可以为零,在这种情况下,它没有类型和值,并且为空。空选项称为“标记”。

   +-------------/-+~~~~~~~~~~~~~/~+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+
   |   length    \ |    type     \ |            value              |
   +-------------/-+~~~~~~~~~~~~~/~+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~/
                   ^                                               ^
                   +-------- length bytes long (may be 0) ---------+
        
   +-------------/-+~~~~~~~~~~~~~/~+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+
   |   length    \ |    type     \ |            value              |
   +-------------/-+~~~~~~~~~~~~~/~+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~/
                   ^                                               ^
                   +-------- length bytes long (may be 0) ---------+
        
   struct option_t
   {
       vlu_t length :variable*8; // "L"
       if(length > 0)
       {
           struct {
               vlu_t   type :variable*8;   // "T"
               uint8_t value[remainder()]; // "V"
           } payload :length*8;
       }
   } :variable*8;
        
   struct option_t
   {
       vlu_t length :variable*8; // "L"
       if(length > 0)
       {
           struct {
               vlu_t   type :variable*8;   // "T"
               uint8_t value[remainder()]; // "V"
           } payload :length*8;
       }
   } :variable*8;
        
                             +---/---/-------+
                             | L \ T \   V   |
                             +---/---/-------+
        
                             +---/---/-------+
                             | L \ T \   V   |
                             +---/---/-------+
        

Figure 2: Option Depiction in Following Diagrams

图2:下图中的选项描述

2.1.4. Option List
2.1.4. 选项列表

An Option List is a sequence of zero or more non-empty Options terminated by a Marker.

选项列表是以标记终止的零个或多个非空选项的序列。

   +~~~/~~~/~~~~~~~+               +~~~/~~~/~~~~~~~+-------------/-+
   | L \ T \   V   |...............| L \ T \   V   |       0     \ |
   +~~~/~~~/~~~~~~~+               +~~~/~~~/~~~~~~~+-------------/-+
   ^                                               ^     Marker
   +------- zero or more non-empty Options --------+ (empty Option)
        
   +~~~/~~~/~~~~~~~+               +~~~/~~~/~~~~~~~+-------------/-+
   | L \ T \   V   |...............| L \ T \   V   |       0     \ |
   +~~~/~~~/~~~~~~~+               +~~~/~~~/~~~~~~~+-------------/-+
   ^                                               ^     Marker
   +------- zero or more non-empty Options --------+ (empty Option)
        
   struct optionList_t
   {
       do
       {
           option_t option :variable*8;
       } while(option.length > 0);
   } :variable*8;
        
   struct optionList_t
   {
       do
       {
           option_t option :variable*8;
       } while(option.length > 0);
   } :variable*8;
        
2.1.5. Internet Socket Address (Address)
2.1.5. Internet套接字地址(地址)

When communicating an Internet socket address (a combination of a 32-bit IPv4 [RFC0791] or 128-bit IPv6 [RFC2460] address and a 16-bit port number) to another RTMFP, this encoding is used. This encoding additionally allows an address to be tagged with an origin type, which an RTMFP MAY use to modify the use or disposition of the address.

在将Internet套接字地址(32位IPv4[RFC0791]或128位IPv6[RFC2460]地址和16位端口号的组合)通信到另一个RTMFP时,使用此编码。此编码还允许使用源类型标记地址,RTMFP可使用该类型修改地址的使用或处置。

                                                        1
    0 1 2 3 4 5 6 7                 0 1 2 3 4 5 6 7|8 9 0 1 2 3 4 5
   +-+-+-+-+-+-+-+-+-----/.../-----+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |I|         | O |    Internet   |                               |
   |P|0 0 0 0 0| R |    address    |              port             |
   |6|   rsv   | I |32 or 128 bits |                               |
   +-+-+-+-+-+-+-+-+-----/.../-----+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
        
                                                        1
    0 1 2 3 4 5 6 7                 0 1 2 3 4 5 6 7|8 9 0 1 2 3 4 5
   +-+-+-+-+-+-+-+-+-----/.../-----+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |I|         | O |    Internet   |                               |
   |P|0 0 0 0 0| R |    address    |              port             |
   |6|   rsv   | I |32 or 128 bits |                               |
   +-+-+-+-+-+-+-+-+-----/.../-----+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
        
   struct address_t
   {
       bool_t  inet6    :1;     // "IP6"
       uintn_t reserved :5 = 0; // "rsv"
       uintn_t origin   :2;     // "ORI"
       if(inet6)
           uint128_t ipAddress;
       else
           uint32_t ipAddress;
       uint16_t port;
   } :variable*8;
        
   struct address_t
   {
       bool_t  inet6    :1;     // "IP6"
       uintn_t reserved :5 = 0; // "rsv"
       uintn_t origin   :2;     // "ORI"
       if(inet6)
           uint128_t ipAddress;
       else
           uint32_t ipAddress;
       uint16_t port;
   } :variable*8;
        

inet6: If set, the Internet address is a 128-bit IPv6 address. If clear, the Internet address is a 32-bit IPv4 address.

inet6:如果设置,则Internet地址为128位IPv6地址。如果清除,则Internet地址为32位IPv4地址。

origin: The origin tag of this address. Possible values are:

来源:此地址的来源标签。可能的值为:

0: Unknown, unspecified, or "other"

0:未知、未指定或“其他”

1: Address was reported by the origin as a local, directly attached interface address

1:源站将地址报告为本地直接连接的接口地址

2: Address was observed to be the source address from which a packet was received (a "reflexive transport address" in the terminology of [RFC5389])

2:观察到地址是接收数据包的源地址(术语[RFC5389]中的“自反传输地址”)

3: Address is a relay, proxy, or introducer (a Redirector and/or Forwarder)

3:地址是中继、代理或介绍人(重定向器和/或转发器)

ipAddress: The Internet address, in network byte order.

ipAddress:按网络字节顺序排列的Internet地址。

port: The 16-bit port number, in network byte order.

端口:16位端口号,按网络字节顺序排列。

2.2. Network Layer
2.2. 网络层
2.2.1. Encapsulation
2.2.1. 封装

RTMFP Multiplex packets are usually carried in UDP [RFC0768] datagrams so that they may transit commonly deployed NATs and firewalls, and so that RTMFP may be implemented on commonly deployed operating systems without special privileges or permissions.

RTMFP多路复用数据包通常以UDP[RFC0768]数据报的形式传输,以便它们可以传输通常部署的NAT和防火墙,并且可以在通常部署的操作系统上实现RTMFP,而无需特殊特权或权限。

RTMFP Multiplex packets MAY be carried by any suitable datagram transport or encapsulation where endpoints are addressed by an Internet socket address (that is, an IPv4 or IPv6 address and a 16-bit port number).

RTMFP多路复用分组可由任何合适的数据报传输或封装来承载,其中端点由因特网套接字地址(即,IPv4或IPv6地址和16位端口号)寻址。

The choice of port numbers is not mandated by this specification. Higher protocol layers or the application define the port numbers used.

本规范不强制要求选择端口号。更高的协议层或应用程序定义所使用的端口号。

2.2.2. Multiplex
2.2.2. 多路复用
    0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |                 Scrambled Session ID (SSID)                   |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |             e             first32[0]                          |
   |- - - - - -  n  - - - - - - - - - - - - - - - - - - - - - - - -|
   |             c             first32[1]                          |
   +- - - - - -  r  - - - - - - - - - - - - - - - - - - - - - - - -+
   |             y                                                 |
   |             pted packet                                       |
   +---------------------------------------------------------------/
        
    0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |                 Scrambled Session ID (SSID)                   |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |             e             first32[0]                          |
   |- - - - - -  n  - - - - - - - - - - - - - - - - - - - - - - - -|
   |             c             first32[1]                          |
   +- - - - - -  r  - - - - - - - - - - - - - - - - - - - - - - - -+
   |             y                                                 |
   |             pted packet                                       |
   +---------------------------------------------------------------/
        
   struct multiplex_t
   {
       uint32_t scrambledSessionID; // "SSID"
       union {
           uint32_t first32[2]; // see note
           uint8_t  encryptedPacket[remainder()];
       } :(encapsulation.length - 4)*8;
        
   struct multiplex_t
   {
       uint32_t scrambledSessionID; // "SSID"
       union {
           uint32_t first32[2]; // see note
           uint8_t  encryptedPacket[remainder()];
       } :(encapsulation.length - 4)*8;
        
       // if encryptedPacket is less than 8 bytes long, treat it
       // as if it were end-padded with 0s for the following:
       sessionID = scrambledSessionID XOR first32[0] XOR first32[1];
   } :encapsulation.length*8;
        
       // if encryptedPacket is less than 8 bytes long, treat it
       // as if it were end-padded with 0s for the following:
       sessionID = scrambledSessionID XOR first32[0] XOR first32[1];
   } :encapsulation.length*8;
        

The 32-bit Scrambled Session ID is the 32-bit session ID modified by performing a bitwise exclusive-or with the bitwise exclusive-or of the first two 32-bit words of the encrypted packet.

32位加扰会话ID是通过对加密分组的前两个32位字的位异或执行位异或而修改的32位会话ID。

The session ID is a 32-bit value that the receiver has requested to be used by the sender when sending packets to this receiver (Sections 2.3.7 and 2.3.8). The session ID identifies the session to which this packet belongs and the decryption key to be used to decrypt the encrypted packet.

会话ID是一个32位的值,接收方在向该接收方发送数据包时请求发送方使用该值(第2.3.7节和第2.3.8节)。会话ID标识此数据包所属的会话以及用于解密加密数据包的解密密钥。

Note: Session ID 0 (prior to scrambling) denotes the startup pseudo-session and implies the Default Session Key.

注意:会话ID 0(加扰之前)表示启动伪会话,并表示默认会话密钥。

Note: If the encrypted packet is less than 8 bytes long, then for the scrambling operation, perform the exclusive-or as though the encrypted packet were end-padded with enough 0-bytes to bring its length to 8.

注意:如果加密数据包的长度小于8字节,则对于加扰操作,执行异或,就好像加密数据包的末尾填充了足够的0字节,以使其长度达到8。

2.2.3. Encryption
2.2.3. 加密

RTMFP packets are encrypted according to a Cryptography Profile. This specification doesn't define a Cryptography Profile or mandate a particular choice of cryptography. The application defines the cryptographic syntax and algorithms.

RTMFP数据包根据加密配置文件进行加密。本规范未定义加密配置文件,也未指定特定的加密选项。应用程序定义加密语法和算法。

Packet encryption is RECOMMENDED to be a block cipher operating in Cipher Block Chaining [CBC] or similar mode. Encrypted packets MUST be decipherable without inter-packet dependency, since packets may be lost, duplicated, or reordered in the network.

分组加密建议为在密码分组链[CBC]或类似模式下运行的分组密码。由于数据包可能在网络中丢失、复制或重新排序,因此加密的数据包必须能够在没有数据包间依赖的情况下进行解密。

The packet encryption layer is responsible for data integrity and authenticity of packets, for example by means of a checksum or cryptographic message authentication code. To mitigate replay attacks, data integrity SHOULD comprise duplicate packet detection, for example by means of a session-wide packet sequence number. The packet encryption layer SHALL discard a received packet that does not pass integrity or authenticity tests.

包加密层负责包的数据完整性和真实性,例如通过校验和或加密消息认证码。为了减轻重播攻击,数据完整性应包括重复数据包检测,例如通过会话范围的数据包序列号。数据包加密层应丢弃未通过完整性或真实性测试的接收数据包。

Note that the structures described below are of plain, unencrypted packets. Encrypted packets MUST be decrypted according to the Session Key associated with the Multiplex Session ID before being interpreted according to this specification.

注意,下面描述的结构是普通的、未加密的数据包。在根据本规范进行解释之前,必须根据与多路复用会话ID相关联的会话密钥对加密数据包进行解密。

The Cryptography Profile defines a well-known Default Session Key that is used at session startup, during which per-session key(s) are negotiated by the two endpoints. A session ID of zero denotes use of the Default Session Key. The Default Session Key is also used with

加密配置文件定义了会话启动时使用的众所周知的默认会话密钥,在此期间,每个会话密钥由两个端点协商。会话ID为零表示使用默认会话密钥。默认会话密钥也用于

non-zero session IDs during the latter phases of session startup (Sections 2.3.6 and 2.3.8). See Security Considerations (Section 5) for more about the Default Session Key.

会话启动后期阶段的非零会话ID(第2.3.6节和第2.3.8节)。有关默认会话密钥的更多信息,请参阅安全注意事项(第5节)。

2.2.4. Packet
2.2.4. 小包裹

An (unencrypted, plain) RTMFP packet consists of a variable sized common header, zero or more chunks, and padding. Padding can be inserted by the encryption layer of the sender to meet cipher block size constraints and is ignored by the receiver. A sender's encryption layer MAY pad the end of a packet with bytes with value 0xff such that the resulting packet is a natural and appropriate size for the cipher. Alternatively, the Cryptography Profile MAY define its own framing and padding scheme, if needed, such that decrypted packets are compatible with the syntax defined in this section.

一个(未加密的,普通的)RTMFP数据包由一个可变大小的公共头、零个或多个块和填充组成。发送方的加密层可以插入填充,以满足密码块大小限制,接收方可以忽略填充。发送方的加密层可以用值为0xff的字节填充数据包的末尾,这样生成的数据包对于密码来说是一个自然和适当的大小。或者,如果需要,加密配置文件可以定义其自己的帧和填充方案,使得解密的分组与本节中定义的语法兼容。

    0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7
   +-+-+-+-+-+-+-+-+
   |T|T| r |T|T| M |
   |C|C| s |S|S| O |
   | |R| v | |E| D |
   +-+-+-+-+-+-+-+-+
   +~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+
   |        if(TS) timestamp       |     if(TSE) timestampEcho     |
   +~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+
   +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+
   |                             Chunk                             |
   +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~/
                                   :
                                   :
   +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+
   |                             Chunk                             |
   +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~/
   +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+
   |                            padding                            |
   +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~/
        
    0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7
   +-+-+-+-+-+-+-+-+
   |T|T| r |T|T| M |
   |C|C| s |S|S| O |
   | |R| v | |E| D |
   +-+-+-+-+-+-+-+-+
   +~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+
   |        if(TS) timestamp       |     if(TSE) timestampEcho     |
   +~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+
   +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+
   |                             Chunk                             |
   +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~/
                                   :
                                   :
   +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+
   |                             Chunk                             |
   +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~/
   +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+
   |                            padding                            |
   +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~/
        
   struct packet_t
   {
       bool_t  timeCritical         :1; // "TC"
       bool_t  timeCriticalReverse  :1; // "TCR"
       uintn_t reserved             :2; // "rsv"
       bool_t  timestampPresent     :1; // "TS"
       bool_t  timestampEchoPresent :1; // "TSE"
       uintn_t mode                 :2; // "MOD"
       if(0 != mode)
       {
           if(timestampPresent)
               uint16_t timestamp;
           if(timestampEchoPresent)
               uint16_t timestampEcho;
           while(remainder() > 2)
           {
               uint8_t  chunkType;
               uint16_t chunkLength;
               if(remainder() < chunkLength)
                   break;
               uint8_t  chunkPayload[chunkLength];
           } // chunks
           uint8_t padding[remainder()];
       }
   } :plainPacket.length*8;
        
   struct packet_t
   {
       bool_t  timeCritical         :1; // "TC"
       bool_t  timeCriticalReverse  :1; // "TCR"
       uintn_t reserved             :2; // "rsv"
       bool_t  timestampPresent     :1; // "TS"
       bool_t  timestampEchoPresent :1; // "TSE"
       uintn_t mode                 :2; // "MOD"
       if(0 != mode)
       {
           if(timestampPresent)
               uint16_t timestamp;
           if(timestampEchoPresent)
               uint16_t timestampEcho;
           while(remainder() > 2)
           {
               uint8_t  chunkType;
               uint16_t chunkLength;
               if(remainder() < chunkLength)
                   break;
               uint8_t  chunkPayload[chunkLength];
           } // chunks
           uint8_t padding[remainder()];
       }
   } :plainPacket.length*8;
        

timeCritical: Time Critical Forward Notification. If set, indicates that this packet contains real-time user data.

时间关键型:时间关键型转发通知。如果设置,则表示此数据包包含实时用户数据。

timeCriticalReverse: Time Critical Reverse Notification. If set, indicates that the sender is currently receiving packets on other sessions that have the timeCritical flag set.

timeCriticalReverse:时间关键型反向通知。如果设置,则表示发送方当前正在其他会话上接收设置了时间关键标志的数据包。

timestampPresent: If set, indicates that the timestamp field is present. If clear, there is no timestamp field.

timestamp present:如果设置,则表示时间戳字段存在。如果清除,则没有时间戳字段。

timestampEchoPresent: If set, indicates that the timestamp echo field is present. If clear, there is no timestamp echo field.

timestamp EchoPresent:如果设置,则表示timestamp echo字段存在。如果清除,则没有时间戳回波字段。

mode: The mode of this packet. See below for additional discussion of packet modes. Possible values are:

模式:此数据包的模式。有关数据包模式的更多讨论,请参见下文。可能的值为:

0: Forbidden value

0:禁止值

1: Initiator Mark

1:启动器标记

2: Responder Mark

2:应答器标记

3: Startup

3:启动

timestamp: If the timestampPresent flag is set, this field is present and contains the low 16 bits of the sender's 250 Hz clock (4 milliseconds per tick) at transmit time. The sender's clock MAY have its origin at any time in the past.

timestamp:如果设置了timestampPresent标志,则此字段存在,并包含发送时发送方250 Hz时钟的低16位(每滴答4毫秒)。发送方的时钟可能在过去的任何时间都有其来源。

timestampEcho: If the timestampEchoPresent flag is set, this field is present and contains the sender's estimate of what the timestamp field of a packet received from the other end would be at the time this packet was transmitted, using the method described in Section 3.5.2.2.

timestampEcho:如果设置了timestampEchoPresent标志,则该字段存在,并包含发送方使用第3.5.2.2节中描述的方法对从另一端接收的数据包的时间戳字段在传输该数据包时的估计值。

chunks: Zero or more chunks follow the header. It is RECOMMENDED that a packet contain at least one chunk.

块:标题后面有零个或多个块。建议数据包至少包含一个区块。

padding: Zero or more bytes of padding follow the chunks. The following conditions indicate padding:

填充:块后面有零个或多个字节的填充。以下条件表示填充:

* Fewer than three bytes (the size of a chunk header) remain in the packet.

* 数据包中保留的字节数(块头的大小)少于三个。

* The chunkLength field of what would be the current chunk header indicates that the hypothetical chunk payload wouldn't fit in the remaining bytes of the packet.

* 当前块头的chunkLength字段表示假设的块有效负载不适合数据包的剩余字节。

Packet mode 0 is not allowed. Packets marked with this mode are invalid and MUST be discarded.

不允许使用数据包模式0。标记有此模式的数据包无效,必须丢弃。

The original initiator of a session MUST mark all non-startup packets it sends in that session with packet mode 1 ("Initiator Mark"). It SHOULD ignore any packet received in that session with packet mode 1.

会话的原始启动器必须使用数据包模式1(“启动器标记”)标记其在该会话中发送的所有非启动数据包。它应该忽略该会话中使用数据包模式1接收到的任何数据包。

The original responder of a session MUST mark all non-startup packets it sends in that session with packet mode 2 ("Responder Mark"). It SHOULD ignore any packet received in that session with packet mode 2.

会话的原始响应程序必须使用数据包模式2(“响应程序标记”)标记其在该会话中发送的所有非启动数据包。它应该忽略该会话中使用数据包模式2接收到的任何数据包。

Packet mode 3 is for session startup. Session startup chunks are only allowed in packets with this mode.

数据包模式3用于会话启动。会话启动块仅允许在此模式下的数据包中使用。

Chunks that are not for session startup are only allowed in packets with modes 1 or 2.

不用于会话启动的块仅允许在模式为1或2的数据包中使用。

2.3. Chunks
2.3. 大块
    0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |   chunkType   |          chunkLength          |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+
   |        chunkPayload (chunkLength bytes, may be zero)          |
   +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~/
        
    0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |   chunkType   |          chunkLength          |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+
   |        chunkPayload (chunkLength bytes, may be zero)          |
   +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~/
        
   struct chunk_t
   {
       uint8_t  chunkType;
       uint16_t chunkLength;
       uint8_t  chunkPayload[chunkLength];
   } :variable*8;
        
   struct chunk_t
   {
       uint8_t  chunkType;
       uint16_t chunkLength;
       uint8_t  chunkPayload[chunkLength];
   } :variable*8;
        

chunkType: The chunk type code.

chunkType:块类型代码。

chunkLength: The size, in bytes, of the chunk payload.

chunkLength:数据块有效负载的大小(以字节为单位)。

chunkPayload: The type-specific payload of this chunk, chunkLength bytes in length (may be empty).

chunkPayload:此区块的特定于类型的有效负载,chunkLength长度为字节(可能为空)。

Defined chunk types are enumerated here in the order they might be encountered in the course of a typical session. The following chunk type codes are defined:

此处按在典型会话过程中可能遇到的顺序枚举已定义的块类型。定义了以下区块类型代码:

0x7f: Packet Fragment (Section 2.3.1)

0x7f:数据包片段(第2.3.1节)

0x30: Initiator Hello (Section 2.3.2)

0x30:启动器你好(第2.3.2节)

0x0f: Forwarded Initiator Hello (Section 2.3.3)

0x0f:转发的启动器你好(第2.3.3节)

0x70: Responder Hello (Section 2.3.4)

0x70:响应者你好(第2.3.4节)

0x71: Responder Redirect (Section 2.3.5)

0x71:响应程序重定向(第2.3.5节)

0x79: RHello Cookie Change (Section 2.3.6)

0x79:RHello Cookie更改(第2.3.6节)

0x38: Initiator Initial Keying (Section 2.3.7)

0x38:启动器初始键控(第2.3.7节)

0x78: Responder Initial Keying (Section 2.3.8)

0x78:应答器初始键控(第2.3.8节)

0x01: Ping (Section 2.3.9)

0x01:Ping(第2.3.9节)

0x41: Ping Reply (Section 2.3.10)

0x41:Ping回复(第2.3.10节)

0x10: User Data (Section 2.3.11)

0x10:用户数据(第2.3.11节)

0x11: Next User Data (Section 2.3.12)

0x11:下一个用户数据(第2.3.12节)

0x50: Data Acknowledgement Bitmap (Section 2.3.13)

0x50:数据确认位图(第2.3.13节)

0x51: Data Acknowledgement Ranges (Section 2.3.14)

0x51:数据确认范围(第2.3.14节)

0x18: Buffer Probe (Section 2.3.15)

0x18:缓冲探头(第2.3.15节)

0x5e: Flow Exception Report (Section 2.3.16)

0x5e:流异常报告(第2.3.16节)

0x0c: Session Close Request (Section 2.3.17)

0x0c:会话关闭请求(第2.3.17节)

0x4c: Session Close Acknowledgement (Section 2.3.18)

0x4c:会话结束确认(第2.3.18节)

0x00: Ignore/Padding

0x00:忽略/填充

0xff: Ignore/Padding

0xff:忽略/填充

A receiver MUST ignore a chunk having an unrecognized chunk type code. A receiver MUST ignore a chunk appearing in a packet having a mode inappropriate to that chunk type.

接收方必须忽略具有无法识别的区块类型代码的区块。接收方必须忽略数据包中出现的块,该数据包的模式不适合该块类型。

Unless specified otherwise, if a chunk has a syntax or processing error (for example, the chunk's payload field is not long enough to contain the specified syntax elements), the chunk SHALL be ignored as though it was not present in the packet, and parsing and processing SHALL commence with the next chunk in the packet, if any.

除非另有规定,否则如果块有语法或处理错误(例如,块的有效负载字段不够长,无法包含指定的语法元素),则应忽略该块,就像它不在数据包中一样,并且解析和处理应从数据包中的下一个块(如果有)开始。

2.3.1. Packet Fragment Chunk
2.3.1. 数据包片段块

This chunk is used to divide a plain RTMFP packet (Section 2.2.4) that is unavoidably larger than the path MTU (such as session startup packets containing Responder Hello (Section 2.3.4) or Initiator Initial Keying (Section 2.3.7) chunks with large certificates) into segments that do not exceed the path MTU, and to allow the segments to be sent through the network at a moderated rate to avoid jamming interfaces, links, or paths.

此数据块用于将不可避免地大于路径MTU的普通RTMFP数据包(第2.2.4节)划分为不超过路径MTU的数据段(例如,包含响应者Hello(第2.3.4节)或启动器初始密钥(第2.3.7节)具有大证书的数据块的会话启动数据包),并允许段以适当的速率通过网络发送,以避免干扰接口、链路或路径。

    0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |      0x7f     |          chunkLength          |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   +-+-+-+-+-+-+-+-+-------------/-+-------------/-+
   |M|  reserved   |   packetID  \ | fragmentNum \ |
   +-+-+-+-+-+-+-+-+-------------/-+-------------/-+
   +---------------------------------------------------------------+
   |                         packetFragment                        |
   +---------------------------------------------------------------/
        
    0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |      0x7f     |          chunkLength          |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   +-+-+-+-+-+-+-+-+-------------/-+-------------/-+
   |M|  reserved   |   packetID  \ | fragmentNum \ |
   +-+-+-+-+-+-+-+-+-------------/-+-------------/-+
   +---------------------------------------------------------------+
   |                         packetFragment                        |
   +---------------------------------------------------------------/
        
   struct fragmentChunkPayload_t
   {
       bool_t  moreFragments :1; // M
       uintn_t reserved      :7;
       vlu_t   packetID      :variable*8;
       vlu_t   fragmentNum   :variable*8;
       uint8_t packetFragment[remainder()];
   } :chunkLength*8;
        
   struct fragmentChunkPayload_t
   {
       bool_t  moreFragments :1; // M
       uintn_t reserved      :7;
       vlu_t   packetID      :variable*8;
       vlu_t   fragmentNum   :variable*8;
       uint8_t packetFragment[remainder()];
   } :chunkLength*8;
        

moreFragments: If set, the indicated packet comprises additional fragments. If clear, this fragment is the final fragment of the packet.

moreFragments:如果设置,则指示的数据包包含额外的片段。如果清除,则此片段是数据包的最终片段。

reserved: Reserved for future use.

保留:保留供将来使用。

packetID: VLU, the identifier of this segmented packet. All fragments of the same packet have the same packetID.

packetID:VLU,此分段数据包的标识符。同一数据包的所有片段都具有相同的packetID。

fragmentNum: VLU, the index of this fragment of the indicated packet. The first fragment of the packet MUST be index 0. Fragments are numbered consecutively.

fragmentNum:VLU,指示数据包的此片段的索引。数据包的第一个片段必须是索引0。碎片按顺序编号。

packetFragment: The bytes of the indicated segment of the indicated original plain RTMFP packet. A packetFragment MUST NOT be empty.

packetFragment:指示的原始纯RTMFP数据包的指示段的字节。packetFragment不能为空。

The use of this mechanism is detailed in Section 3.4.

第3.4节详细介绍了该机制的使用。

2.3.2. Initiator Hello Chunk (IHello)
2.3.2. 启动器Hello区块(IHello)

This chunk is sent by the initiator of a new session to begin the startup handshake. This chunk is only allowed in a packet with Session ID 0, encrypted with the Default Session Key, and having packet mode 3 (Startup).

此区块由新会话的发起方发送,以开始启动握手。此区块仅允许在会话ID为0、使用默认会话密钥加密且具有数据包模式3(启动)的数据包中使用。

    0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |      0x30     |          chunkLength          |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   +-------------/-+-----------------------------------------------+
   |  epdLength  \ |    endpointDiscriminator (epdLength bytes)    |
   +-------------/-+-----------------------------------------------/
   +---------------------------------------------------------------+
   |                              tag                              |
   +---------------------------------------------------------------/
        
    0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |      0x30     |          chunkLength          |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   +-------------/-+-----------------------------------------------+
   |  epdLength  \ |    endpointDiscriminator (epdLength bytes)    |
   +-------------/-+-----------------------------------------------/
   +---------------------------------------------------------------+
   |                              tag                              |
   +---------------------------------------------------------------/
        
   struct ihelloChunkPayload_t
   {
       vlu_t   epdLength :variable*8;
       uint8_t endpointDiscriminator[epdLength];
       uint8_t tag[remainder()];
   } :chunkLength*8;
        
   struct ihelloChunkPayload_t
   {
       vlu_t   epdLength :variable*8;
       uint8_t endpointDiscriminator[epdLength];
       uint8_t tag[remainder()];
   } :chunkLength*8;
        

epdLength: VLU, the length of the following endpointDiscriminator field in bytes.

epdLength:VLU,以下endpointDiscriminator字段的长度(以字节为单位)。

endpointDiscriminator: The Endpoint Discriminator for the identity with which the initiator wants to communicate.

endpointDiscriminator:启动器要与之通信的标识的端点鉴别器。

tag: Initiator-provided data to be returned in a Responder Hello's tagEcho field. The tag/tagEcho is used to match Responder Hellos to the initiator's session startup state independent of the responder's address.

标记:发起者提供了要在响应者Hello的tagEcho字段中返回的数据。tag/tagEcho用于将响应程序hello与发起程序的会话启动状态相匹配,而与响应程序的地址无关。

The use of IHello is detailed in Section 3.5.1.

IHello的使用详见第3.5.1节。

2.3.3. Forwarded Initiator Hello Chunk (FIHello)
2.3.3. 转发的启动器Hello块(FIHello)

This chunk is sent on behalf of an initiator by a Forwarder. It is only allowed in packets of an established session having packet mode 1 or 2. A receiver MAY treat this chunk as though it was an Initiator Hello received directly from replyAddress. Alternatively, if the receiver is selected by the Endpoint Discriminator, it MAY respond to replyAddress with an Implied Redirect (Section 2.3.5).

此区块由转发器代表发起方发送。它仅允许在具有分组模式1或2的已建立会话的分组中使用。接收者可以将此区块视为直接从replyAddress接收的启动器Hello。或者,如果端点鉴别器选择了接收器,则接收器可能会以隐含重定向响应replyAddress(第2.3.5节)。

    0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |      0x0f     |          chunkLength          |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   +-------------/-+-----------------------------------------------+
   |  epdLength  \ |    endpointDiscriminator (epdLength bytes)    |
   +-------------/-+-----------------------------------------------/
   +---------------------------------------------------------------+
   |                          replyAddress                         |
   +---------------------------------------------------------------/
   +---------------------------------------------------------------+
   |                              tag                              |
   +---------------------------------------------------------------/
        
    0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |      0x0f     |          chunkLength          |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   +-------------/-+-----------------------------------------------+
   |  epdLength  \ |    endpointDiscriminator (epdLength bytes)    |
   +-------------/-+-----------------------------------------------/
   +---------------------------------------------------------------+
   |                          replyAddress                         |
   +---------------------------------------------------------------/
   +---------------------------------------------------------------+
   |                              tag                              |
   +---------------------------------------------------------------/
        
   struct fihelloChunkPayload_t
   {
       vlu_t     epdLength :variable*8;
       uint8_t   endpointDiscriminator[epdLength];
       address_t replyAddress :variable*8;
       uint8_t   tag[remainder()];
   } :chunkLength*8;
        
   struct fihelloChunkPayload_t
   {
       vlu_t     epdLength :variable*8;
       uint8_t   endpointDiscriminator[epdLength];
       address_t replyAddress :variable*8;
       uint8_t   tag[remainder()];
   } :chunkLength*8;
        

epdLength: VLU, the length of the following endpointDiscriminator field in bytes.

epdLength:VLU,以下endpointDiscriminator字段的长度(以字节为单位)。

endpointDiscriminator: The Endpoint Discriminator for the identity with which the original initiator wants to communicate, copied from the original Initiator Hello.

endpointDiscriminator:原始启动器想要与其通信的标识的端点鉴别器,从原始启动器Hello复制而来。

replyAddress: Address format (Section 2.1.5), the address that the forwarding node derived from the received Initiator Hello, to which the receiver should respond.

replyAddress:地址格式(第2.1.5节),转发节点从接收到的启动器Hello派生的地址,接收方应响应该地址。

tag: Copied from the original Initiator Hello.

标记:从原始启动器复制,您好。

The use of FIHello is detailed in Section 3.5.1.5.

第3.5.1.5节详细介绍了FIHello的使用。

2.3.4. Responder Hello Chunk (RHello)
2.3.4. 响应程序Hello Chunk(RHello)

This chunk is sent by a responder in response to an Initiator Hello or Forwarded Initiator Hello if the Endpoint Discriminator indicates the responder's identity. This chunk is only allowed in a packet with Session ID 0, encrypted with the Default Session Key, and having packet mode 3 (Startup).

如果端点鉴别器指示响应者的身份,则响应者发送此区块以响应启动器Hello或转发的启动器Hello。此区块仅允许在会话ID为0、使用默认会话密钥加密且具有数据包模式3(启动)的数据包中使用。

    0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |      0x70     |          chunkLength          |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   +-------------/-+-----------------------------------------------+
   |  tagLength  \ |            tagEcho (tagLength bytes)          |
   +-------------/-+-----------------------------------------------/
   +-------------/-+-----------------------------------------------+
   | cookieLength\ |           cookie (cookieLength bytes)         |
   +-------------/-+-----------------------------------------------/
   +---------------------------------------------------------------+
   |                     responderCertificate                      |
   +---------------------------------------------------------------/
        
    0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |      0x70     |          chunkLength          |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   +-------------/-+-----------------------------------------------+
   |  tagLength  \ |            tagEcho (tagLength bytes)          |
   +-------------/-+-----------------------------------------------/
   +-------------/-+-----------------------------------------------+
   | cookieLength\ |           cookie (cookieLength bytes)         |
   +-------------/-+-----------------------------------------------/
   +---------------------------------------------------------------+
   |                     responderCertificate                      |
   +---------------------------------------------------------------/
        
   struct rhelloChunkPayload_t
   {
       vlu_t   tagLength :variable*8;
       uint8_t tagEcho[tagLength];
       vlu_t   cookieLength :variable*8;
       uint8_t cookie[cookieLength];
       uint8_t responderCertificate[remainder()];
   } :chunkLength*8;
        
   struct rhelloChunkPayload_t
   {
       vlu_t   tagLength :variable*8;
       uint8_t tagEcho[tagLength];
       vlu_t   cookieLength :variable*8;
       uint8_t cookie[cookieLength];
       uint8_t responderCertificate[remainder()];
   } :chunkLength*8;
        

tagLength: VLU, the length of the following tagEcho field in bytes.

tagLength:VLU,以下tagEcho字段的长度(字节)。

tagEcho: The tag from the Initiator Hello, unaltered.

tagEcho:来自启动器Hello的标记,未更改。

cookieLength: VLU, the length of the following cookie field in bytes.

cookieLength:VLU,以下cookie字段的长度(以字节为单位)。

cookie: Responder-created state data to authenticate a future Initiator Initial Keying message (in order to prevent denial-of-service attacks).

cookie:响应程序创建状态数据以验证未来的启动器初始密钥消息(以防止拒绝服务攻击)。

responderCertificate: The responder's cryptographic credentials.

responderCertificate:响应者的加密凭据。

Note: This specification doesn't mandate a specific choice of certificate format. The Cryptography Profile determines the syntax, algorithms, and interpretation of the responderCertificate.

注意:本规范不要求特定的证书格式选择。密码配置文件确定responderCertificate的语法、算法和解释。

The use of RHello is detailed in Section 3.5.1.

RHello的使用详见第3.5.1节。

2.3.5. Responder Redirect Chunk (Redirect)
2.3.5. 响应程序重定向块(重定向)

This chunk is sent in response to an Initiator Hello or Forwarded Initiator Hello to indicate that the requested endpoint can be reached at one or more of the indicated addresses. A receiver can add none, some, or all of the indicated addresses to the set of addresses to which it is sending Initiator Hello messages for the opening session associated with tagEcho. This chunk is only allowed in a packet with Session ID 0, encrypted with the Default Session Key, and having packet mode 3 (Startup).

发送此区块是为了响应启动器Hello或转发的启动器Hello,以指示可以在一个或多个指定地址到达请求的端点。接收者可以在与tagEcho关联的开始会话中向其发送启动器Hello消息的地址集中添加任何、部分或所有指示的地址。此区块仅允许在会话ID为0、使用默认会话密钥加密且具有数据包模式3(启动)的数据包中使用。

    0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |      0x71     |          chunkLength          |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   +-------------/-+-----------------------------------------------+
   |  tagLength  \ |            tagEcho (tagLength bytes)          |
   +-------------/-+-----------------------------------------------/
   +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+
   |                     redirectDestination 1                     |
   +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~/
                                   :
                                   :
   +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+
   |                     redirectDestination N                     |
   +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~/
        
    0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |      0x71     |          chunkLength          |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   +-------------/-+-----------------------------------------------+
   |  tagLength  \ |            tagEcho (tagLength bytes)          |
   +-------------/-+-----------------------------------------------/
   +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+
   |                     redirectDestination 1                     |
   +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~/
                                   :
                                   :
   +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+
   |                     redirectDestination N                     |
   +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~/
        
   struct responderRedirectChunkPayload_t
   {
       vlu_t   tagLength :variable*8;
       uint8_t tagEcho[tagLength];
       addressCount = 0;
       while(remainder() > 0)
       {
           address_t redirectDestination :variable*8;
           addressCount++;
       }
       if(0 == addressCount)
           redirectDestination = packetSourceAddress();
   } :chunkLength*8;
        
   struct responderRedirectChunkPayload_t
   {
       vlu_t   tagLength :variable*8;
       uint8_t tagEcho[tagLength];
       addressCount = 0;
       while(remainder() > 0)
       {
           address_t redirectDestination :variable*8;
           addressCount++;
       }
       if(0 == addressCount)
           redirectDestination = packetSourceAddress();
   } :chunkLength*8;
        

tagLength: VLU, the length of the following tagEcho field in bytes.

tagLength:VLU,以下tagEcho字段的长度(字节)。

tagEcho: The tag from the Initiator Hello, unaltered.

tagEcho:来自启动器Hello的标记,未更改。

redirectDestination: (Zero or more) Address format (Section 2.1.5) addresses to add to the opening set for the indicated session.

重定向目的地:(零个或多个)地址格式(第2.1.5节)要添加到指定会话的开始集的地址。

If this chunk lists zero redirectDestination addresses, then this is an Implied Redirect, and the indicated address is the address from which the packet containing this chunk was received.

如果此区块列出零个重定向目标地址,则这是一个隐含的重定向,指示的地址是包含此区块的数据包从中接收的地址。

The use of Redirect is detailed in Sections 3.5.1.1.1, 3.5.1.1.2, and 3.5.1.4.

第3.5.1.1.1、3.5.1.1.2和3.5.1.4节详细介绍了重定向的使用。

2.3.6. RHello Cookie Change Chunk
2.3.6. RHello Cookie更改块

This chunk SHOULD be sent by a responder to an initiator in response to an Initiator Initial Keying if that chunk's cookie appears to have been created by the responder but the cookie is incorrect (for example, it includes a hash of the initiator's address, but the initiator's address is different than the one that elicited the Responder Hello containing the original cookie).

如果该区块的cookie似乎是由响应者创建的,但cookie不正确,则响应者应将该区块发送给启动器,以响应启动器的初始键控(例如,它包含启动器地址的散列,但启动器地址与引发包含原始cookie的响应者Hello的地址不同)。

This chunk is only allowed in a packet encrypted with the Default Session Key and having packet mode 3, and with the session ID indicated in the initiatorSessionID field of the Initiator Initial Keying to which this is a response.

此区块仅允许在使用默认会话密钥加密且具有数据包模式3的数据包中使用,且会话ID在作为响应的启动器初始密钥的Initiator SessionID字段中指示。

    0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |      0x79     |          chunkLength          |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   +-------------/-+-----------------------------------------------+
   | oldCookieLen\ |        oldCookie (oldCookieLen bytes)         |
   +-------------/-+-----------------------------------------------/
   +---------------------------------------------------------------+
   |                           newCookie                           |
   +---------------------------------------------------------------/
        
    0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |      0x79     |          chunkLength          |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   +-------------/-+-----------------------------------------------+
   | oldCookieLen\ |        oldCookie (oldCookieLen bytes)         |
   +-------------/-+-----------------------------------------------/
   +---------------------------------------------------------------+
   |                           newCookie                           |
   +---------------------------------------------------------------/
        
   struct rhelloCookieChangeChunkPayload_t
   {
       vlu_t   oldCookieLen :variable*8;
       uint8_t oldCookie[oldCookieLen];
       uint8_t newCookie[remainder()];
   } :chunkLength*8;
        
   struct rhelloCookieChangeChunkPayload_t
   {
       vlu_t   oldCookieLen :variable*8;
       uint8_t oldCookie[oldCookieLen];
       uint8_t newCookie[remainder()];
   } :chunkLength*8;
        

oldCookieLen: VLU, the length of the following oldCookie field in bytes.

oldCookieLen:VLU,以下oldCookie字段的长度(以字节为单位)。

oldCookie: The cookie that was sent in a previous Responder Hello and Initiator Initial Keying.

oldCookie:在先前的响应程序Hello和启动器初始键控中发送的cookie。

newCookie: The new cookie that the responder would like sent (and signed) in a replacement Initiator Initial Keying. The old and new cookies need not have the same lengths.

newCookie:响应者希望在替换启动器初始密钥中发送(并签名)的新cookie。新旧饼干不必有相同的长度。

On receipt of this chunk, the initiator SHOULD compute, sign, and send a new Initiator Initial Keying having newCookie in place of oldCookie. The use of this chunk is detailed in Section 3.5.1.2.

在收到该区块后,启动器应计算、签名并发送一个新的启动器初始密钥,使用newCookie代替oldCookie。第3.5.1.2节详细介绍了该块的使用。

2.3.7. Initiator Initial Keying Chunk (IIKeying)
2.3.7. 启动器初始密钥块(IIKeying)

This chunk is sent by an initiator to establish a session with a responder. The initiator MUST have obtained a valid cookie to use with the responder, typically by receiving a Responder Hello from it. This chunk is only allowed in a packet with Session ID 0, encrypted with the Default Session Key, and having packet mode 3 (Startup).

此区块由发起方发送,以与响应方建立会话。发起者必须已获得有效的cookie以与响应者一起使用,通常是通过接收来自它的响应者Hello。此区块仅允许在会话ID为0、使用默认会话密钥加密且具有数据包模式3(启动)的数据包中使用。

    0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |      0x38     |          chunkLength          |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |                       initiatorSessionID                      |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   +-------------/-+-----------------------------------------------+
   | cookieLength\ |                  cookieEcho                   |
   +-------------/-+-----------------------------------------------/
   +-------------/-+-----------------------------------------------+
   |  certLength \ |             initiatorCertificate              |
   +-------------/-+-----------------------------------------------/
   +-------------/-+-----------------------------------------------+
   |  skicLength \ |          sessionKeyInitiatorComponent         |
   +-------------/-+-----------------------------------------------/
   +---------------------------------------------------------------+
   |                           signature                           |
   +---------------------------------------------------------------/
        
    0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |      0x38     |          chunkLength          |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |                       initiatorSessionID                      |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   +-------------/-+-----------------------------------------------+
   | cookieLength\ |                  cookieEcho                   |
   +-------------/-+-----------------------------------------------/
   +-------------/-+-----------------------------------------------+
   |  certLength \ |             initiatorCertificate              |
   +-------------/-+-----------------------------------------------/
   +-------------/-+-----------------------------------------------+
   |  skicLength \ |          sessionKeyInitiatorComponent         |
   +-------------/-+-----------------------------------------------/
   +---------------------------------------------------------------+
   |                           signature                           |
   +---------------------------------------------------------------/
        
   struct iikeyingChunkPayload_t
   {
       struct
       {
           uint32_t initiatorSessionID;
           vlu_t    cookieLength :variable*8;
           uint8_t  cookieEcho[cookieLength];
           vlu_t    certLength :variable*8;
           uint8_t  initiatorCertificate[certLength];
           vlu_t    skicLength :variable*8;
           uint8_t  sessionKeyInitiatorComponent[skicLength];
       } initiatorSignedParameters :variable*8;
       uint8_t signature[remainder()];
   } :chunkLength*8;
        
   struct iikeyingChunkPayload_t
   {
       struct
       {
           uint32_t initiatorSessionID;
           vlu_t    cookieLength :variable*8;
           uint8_t  cookieEcho[cookieLength];
           vlu_t    certLength :variable*8;
           uint8_t  initiatorCertificate[certLength];
           vlu_t    skicLength :variable*8;
           uint8_t  sessionKeyInitiatorComponent[skicLength];
       } initiatorSignedParameters :variable*8;
       uint8_t signature[remainder()];
   } :chunkLength*8;
        

initiatorSessionID: The session ID to be used by the responder when sending packets to the initiator.

initiatorSessionID:响应程序向启动器发送数据包时使用的会话ID。

cookieLength: VLU, the length of the following cookieEcho field in bytes.

cookieLength:VLU,以下cookieEcho字段的长度(以字节为单位)。

cookieEcho: The cookie from the Responder Hello, unaltered.

cookieEcho:回应者的曲奇你好,没有改变。

certLength: VLU, the length of the following initiatorCertificate field in bytes.

certLength:VLU,以下initiatorCertificate字段的长度(字节)。

initiatorCertificate: The initiator's identity credentials.

启动器证书:启动器的身份凭据。

skicLength: VLU, the length of the following sessionKeyInitiatorComponent field in bytes.

skicLength:VLU,以下sessionKeyInitiatorComponent字段的长度(以字节为单位)。

sessionKeyInitiatorComponent: The initiator's portion of the session key negotiation according to the Cryptography Profile.

sessionKeyInitiatorComponent:根据加密配置文件,会话密钥协商的发起方部分。

initiatorSignedParameters: The payload portion of this chunk up to the signature field.

initiatorSignedParameters:此区块的有效负载部分,直至签名字段。

signature: The initiator's digital signature of the initiatorSignedParameters according to the Cryptography Profile.

签名:启动器根据加密配置文件对启动器签名参数的数字签名。

Note: This specification doesn't mandate a specific choice of cryptography. The Cryptography Profile determines the syntax, algorithms, and interpretation of the initiatorCertificate, responderCertificate, sessionKeyInitiatorComponent, sessionKeyResponderComponent, and signature, and how the sessionKeyInitiatorComponent and sessionKeyResponderComponent are combined to derive the session keys.

注意:本规范不要求特定的加密选择。密码配置文件确定启动器证书、响应证书、sessionKeyInitiatorComponent、sessionKeyResponderComponent和签名的语法、算法和解释,以及sessionKeyInitiatorComponent和sessionKeyResponderComponent如何组合以派生会话密钥。

The use of IIKeying is detailed in Section 3.5.1.

第3.5.1节详细介绍了IIKeying的使用。

2.3.8. Responder Initial Keying Chunk (RIKeying)
2.3.8. 响应程序初始键控块(RIKeying)

This chunk is sent by a responder in response to an Initiator Initial Keying as the final phase of session startup. This chunk is only allowed in a packet encrypted with the Default Session Key, having packet mode 3 (Startup), and sent to the initiator with the session ID specified by the initiatorSessionID field from the Initiator Initial Keying.

作为会话启动的最后阶段,该区块由响应程序发送,以响应发起程序的初始键控。此区块仅允许在使用默认会话密钥加密的数据包中使用,该数据包具有数据包模式3(启动),并使用启动器初始密钥中initiatorSessionID字段指定的会话ID发送给启动器。

    0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |      0x78     |          chunkLength          |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |                       responderSessionID                      |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   +-------------/-+-----------------------------------------------+
   |  skrcLength \ |         sessionKeyResponderComponent          |
   +-------------/-+-----------------------------------------------/
   +---------------------------------------------------------------+
   |                           signature                           |
   +---------------------------------------------------------------/
        
    0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |      0x78     |          chunkLength          |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |                       responderSessionID                      |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   +-------------/-+-----------------------------------------------+
   |  skrcLength \ |         sessionKeyResponderComponent          |
   +-------------/-+-----------------------------------------------/
   +---------------------------------------------------------------+
   |                           signature                           |
   +---------------------------------------------------------------/
        
   struct rikeyingChunkPayload_t
   {
       struct
       {
           uint32_t responderSessionID;
           vlu_t    skrcLength :variable*8;
           uint8_t  sessionKeyResponderComponent[skrcLength];
       } responderSignedParametersPortion :variable*8;
       uint8_t  signature[remainder()];
   } :chunkLength*8;
        
   struct rikeyingChunkPayload_t
   {
       struct
       {
           uint32_t responderSessionID;
           vlu_t    skrcLength :variable*8;
           uint8_t  sessionKeyResponderComponent[skrcLength];
       } responderSignedParametersPortion :variable*8;
       uint8_t  signature[remainder()];
   } :chunkLength*8;
        
   struct
   {
       responderSignedParametersPortion;
       sessionKeyInitiatorComponent;
   } responderSignedParameters;
        
   struct
   {
       responderSignedParametersPortion;
       sessionKeyInitiatorComponent;
   } responderSignedParameters;
        

responderSessionID: The session ID to be used by the initiator when sending packets to the responder.

responderSessionID:启动器向响应程序发送数据包时使用的会话ID。

skrcLength: VLU, the length of the following sessionKeyResponderComponent field in bytes.

skrcLength:VLU,以下sessionKeyResponderComponent字段的长度(以字节为单位)。

sessionKeyResponderComponent: The responder's portion of the session key negotiation according to the Cryptography Profile.

sessionKeyResponderComponent:根据加密配置文件,会话密钥协商的响应方部分。

responderSignedParametersPortion: The payload portion of this chunk up to the signature field.

responderSignedParametersPortion:此数据块到签名字段的有效负载部分。

signature: The responder's digital signature of the responderSignedParameters (see below) according to the Cryptography Profile.

签名:根据密码配置文件,响应者对响应者签名参数(见下文)的数字签名。

responderSignedParameters: The concatenation of the responderSignedParametersPortion (the payload portion of this chunk up to the signature field) and the sessionKeyInitiatorComponent from the Initiator Initial Keying to which this chunk is a response.

responderSignedParameters:ResponderSignedParametersSportion(此数据块的有效负载部分到签名字段)和来自启动器初始键控的sessionKeyInitiatorComponent(此数据块为响应)的串联。

Note: This specification doesn't mandate a specific choice of cryptography. The Cryptography Profile determines the syntax, algorithms, and interpretation of the initiatorCertificate, responderCertificate, sessionKeyInitiatorComponent, sessionKeyResponderComponent, and signature, and how the sessionKeyInitiatorComponent and sessionKeyResponderComponent are combined to derive the session keys.

注意:本规范不要求特定的加密选择。密码配置文件确定启动器证书、响应证书、sessionKeyInitiatorComponent、sessionKeyResponderComponent和签名的语法、算法和解释,以及sessionKeyInitiatorComponent和sessionKeyResponderComponent如何组合以派生会话密钥。

Once the responder has computed the sessionKeyResponderComponent, it has all of the information and state necessary for an established session with the initiator. Once the responder has sent this chunk to the initiator, the session is established and ready to carry flows of user data.

一旦响应程序计算了sessionKeyResponderComponent,它就拥有与发起程序建立会话所需的所有信息和状态。一旦响应者将该区块发送给发起方,会话就建立并准备好承载用户数据流。

Once the initiator receives, verifies, and processes this chunk, it has all of the information and state necessary for an established session with the responder. The session is established and ready to carry flows of user data.

一旦发起方接收、验证和处理此区块,它就拥有与响应方建立会话所需的所有信息和状态。会话已建立并准备好承载用户数据流。

The use of RIKeying is detailed in Section 3.5.1.

第3.5.1节详细说明了RIKeying的使用。

2.3.9. Ping Chunk
2.3.9. 平块

This chunk is sent in order to elicit a Ping Reply from the receiver. It is only allowed in a packet belonging to an established session and having packet mode 1 or 2.

发送此区块是为了从接收方获取Ping回复。它仅允许在属于已建立会话且具有分组模式1或2的分组中使用。

    0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |      0x01     |          chunkLength          |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+
   |                             message                           |
   +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~/
        
    0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |      0x01     |          chunkLength          |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+
   |                             message                           |
   +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~/
        
   struct pingChunkPayload_t
   {
       uint8_t message[chunkLength];
   } :chunkLength*8;
        
   struct pingChunkPayload_t
   {
       uint8_t message[chunkLength];
   } :chunkLength*8;
        

message: The (potentially empty) message that is expected to be returned by the other end of the session in a Ping Reply.

message:会话另一端在Ping应答中预期返回的(可能为空)消息。

The receiver of this chunk SHOULD reply as immediately as is practical with a Ping Reply.

此数据块的接收者应立即回复Ping回复。

Ping and the expected Ping Reply are typically used for session keepalive, endpoint address change verification, and path MTU discovery. See Section 3.5.4 for details.

Ping和预期的Ping应答通常用于会话保持、端点地址更改验证和路径MTU发现。详见第3.5.4节。

2.3.10. Ping Reply Chunk
2.3.10. Ping回复块

This chunk is sent in response to a Ping chunk. It is only allowed in a packet belonging to an established session and having packet mode 1 or 2.

发送此区块是为了响应Ping区块。它仅允许在属于已建立会话且具有分组模式1或2的分组中使用。

    0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |      0x41     |          chunkLength          |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+
   |                           messageEcho                         |
   +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~/
        
    0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |      0x41     |          chunkLength          |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+
   |                           messageEcho                         |
   +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~/
        
   struct pingReplyChunkPayload_t
   {
       uint8_t messageEcho[chunkLength];
   } :chunkLength*8;
        
   struct pingReplyChunkPayload_t
   {
       uint8_t messageEcho[chunkLength];
   } :chunkLength*8;
        

messageEcho: The message from the Ping to which this is a response, unaltered.

messageEcho:来自Ping的消息,这是响应,未更改。

2.3.11. User Data Chunk
2.3.11. 用户数据块

This chunk is the basic unit of transmission for the user messages of a flow. A user message comprises one or more fragments. Each fragment is carried in its own chunk and has a unique sequence number in its flow. It is only allowed in a packet belonging to an established session and having packet mode 1 or 2.

该区块是流的用户消息的基本传输单元。用户消息包含一个或多个片段。每个片段都包含在自己的块中,并且在其流中具有唯一的序列号。它仅允许在属于已建立会话且具有分组模式1或2的分组中使用。

    0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |      0x10     |          chunkLength          |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   +-+-+-+-+-+-+-+-+
   |O|r| F | r |A|F|
   |P|s| R | s |B|I|
   |T|v| A | v |N|N|
   +-+-+-+-+-+-+-+-+
   +-------------/-+-------------/-+-------------/-+
   |   flowID    \ |     seq#    \ |  fsnOffset  \ |
   +-------------/-+-------------/-+-------------/-+
   +~~~/~~~/~~~~~~~+               +~~~/~~~/~~~~~~~+-------------/-+
   | L \ T \   V   |... options ...| L \ T \   V   |       0     \ |
   \~~~/~~~/~~~~~~~+   [if(OPT)]   +~~~/~~~/~~~~~~~+-------------/-/
   +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+
   |                            userData                           |
   +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~/
        
    0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |      0x10     |          chunkLength          |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   +-+-+-+-+-+-+-+-+
   |O|r| F | r |A|F|
   |P|s| R | s |B|I|
   |T|v| A | v |N|N|
   +-+-+-+-+-+-+-+-+
   +-------------/-+-------------/-+-------------/-+
   |   flowID    \ |     seq#    \ |  fsnOffset  \ |
   +-------------/-+-------------/-+-------------/-+
   +~~~/~~~/~~~~~~~+               +~~~/~~~/~~~~~~~+-------------/-+
   | L \ T \   V   |... options ...| L \ T \   V   |       0     \ |
   \~~~/~~~/~~~~~~~+   [if(OPT)]   +~~~/~~~/~~~~~~~+-------------/-/
   +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+
   |                            userData                           |
   +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~/
        
   struct userDataChunkPayload_t
   {
       bool_t  optionsPresent :1;  // "OPT"
       uintn_t reserved1 :1;       // "rsv"
       uintn_t fragmentControl :2; // "FRA"
           // 0=whole, 1=begin, 2=end, 3=middle
       uintn_t reserved2 :2;       // "rsv"
       bool_t  abandon :1;         // "ABN"
       bool_t  final :1;           // "FIN"
       vlu_t   flowID :variable*8;
       vlu_t   sequenceNumber :variable*8; // "seq#"
       vlu_t   fsnOffset :variable*8;
       forwardSequenceNumber = sequenceNumber - fsnOffset;
       if(optionsPresent)
           optionList_t options :variable*8;
       uint8_t userData[remainder()];
   } :chunkLength*8;
        
   struct userDataChunkPayload_t
   {
       bool_t  optionsPresent :1;  // "OPT"
       uintn_t reserved1 :1;       // "rsv"
       uintn_t fragmentControl :2; // "FRA"
           // 0=whole, 1=begin, 2=end, 3=middle
       uintn_t reserved2 :2;       // "rsv"
       bool_t  abandon :1;         // "ABN"
       bool_t  final :1;           // "FIN"
       vlu_t   flowID :variable*8;
       vlu_t   sequenceNumber :variable*8; // "seq#"
       vlu_t   fsnOffset :variable*8;
       forwardSequenceNumber = sequenceNumber - fsnOffset;
       if(optionsPresent)
           optionList_t options :variable*8;
       uint8_t userData[remainder()];
   } :chunkLength*8;
        

optionsPresent: If set, indicates the presence of an option list before the user data. If clear, there is no option list in this chunk.

optionsPresent:如果设置,则表示在用户数据之前存在选项列表。如果清除,则此区块中没有选项列表。

fragmentControl: Indicates how this fragment is assembled, potentially with others, into a complete user message. Possible values:

fragmentControl:指示如何将此片段(可能与其他片段一起)组装成完整的用户消息。可能值:

0: This fragment is a complete message.

0:此片段是完整的消息。

1: This fragment is the first of a multi-fragment message.

1:这个片段是多片段消息的第一个片段。

2: This fragment is the last of a multi-fragment message.

2:此片段是多片段消息的最后一个片段。

3: This fragment is in the middle of a multi-fragment message.

3:此片段位于多片段消息的中间。

A single-fragment user message has a fragment control of "0-whole". When a message has more than one fragment, the first fragment has a fragment control of "1-begin", then zero or more "3-middle" fragments, and finally a "2-end" fragment. The sequence numbers of a multi-fragment message MUST be contiguous.

单个片段用户消息的片段控件为“0-whole”。当一条消息有多个片段时,第一个片段的片段控制为“1-begin”,然后是零个或多个“3-middle”片段,最后是一个“2-end”片段。多片段消息的序列号必须是连续的。

abandon: If set, this sequence number has been abandoned by the sender. The userData, if any, MUST be ignored.

放弃:如果设置,则此序列号已被发送方放弃。必须忽略userData(如果有)。

final: If set, this is the last sequence number of the flow.

最终:如果设置,这是流的最后序列号。

flowID: VLU, the flow identifier.

flowID:VLU,流标识符。

sequenceNumber: VLU, the sequence number of this fragment. Fragments are assigned contiguous increasing sequence numbers in a flow. The first sequence number of a flow SHOULD be 1. The first sequence number of a flow MUST be greater than zero. Sequence numbers are unbounded and do not wrap.

sequenceNumber:VLU,这个片段的序列号。在流中为片段分配连续递增的序列号。流的第一个序列号应为1。流的第一个序列号必须大于零。序列号是无界的,不换行。

fsnOffset: VLU, the difference between the sequence number and the Forward Sequence Number. This field MUST NOT be zero if the abandon flag is not set. This field MUST NOT be greater than sequenceNumber.

fsnOffset:VLU,序列号和前向序列号之间的差。如果未设置放弃标志,则此字段不得为零。此字段不能大于sequenceNumber。

forwardSequenceNumber: The flow sender will not send (or resend) any fragment with a sequence number less than or equal to the Forward Sequence Number.

forwardSequenceNumber:流发送器不会发送(或重新发送)序列号小于或等于转发序列号的任何片段。

options: If the optionsPresent flag is set, a list of zero or more Options terminated by a Marker is present. See Section 2.3.11.1 for defined options.

选项:如果设置了optionsPresent标志,则会出现由标记终止的零个或多个选项的列表。定义的选项见第2.3.11.1节。

userData: The actual user data for this fragment.

userData:此片段的实际用户数据。

The use of User Data is detailed in Section 3.6.2.

用户数据的使用详见第3.6.2节。

2.3.11.1. Options for User Data
2.3.11.1. 用户数据的选项

This section lists options that may appear in User Data option lists. A conforming implementation MUST support the options in this section.

本节列出可能出现在用户数据选项列表中的选项。一致性实施必须支持本节中的选项。

A flow receiver MUST reject a flow containing a flow option that is not understood if the option type is less than 8192 (0x2000). A flow receiver MUST ignore any flow option that is not understood if the option type is 8192 or greater.

如果选项类型小于8192(0x2000),则流接收器必须拒绝包含无法理解的流选项的流。如果选项类型为8192或更大,则流量接收器必须忽略任何未理解的流量选项。

The following option type codes are defined for User Data:

为用户数据定义了以下选项类型代码:

0x00: User's Per-Flow Metadata (Section 2.3.11.1.1)

0x00:用户的每流元数据(第2.3.11.1.1节)

0x0a: Return Flow Association (Section 2.3.11.1.2)

0x0a:回流关联(第2.3.11.1.2节)

2.3.11.1.1. User's Per-Flow Metadata
2.3.11.1.1. 用户的每流元数据

This option conveys the user's per-flow metadata for the flow to which it's attached.

此选项传递用户附加到的流的每流元数据。

   +-------------/-+-------------/-+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+
   |   length    \ |     0x00    \ |         userMetadata          |
   +-------------/-+-------------/-+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~/
        
   +-------------/-+-------------/-+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+
   |   length    \ |     0x00    \ |         userMetadata          |
   +-------------/-+-------------/-+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~/
        
   struct userMetadataOptionValue_t
   {
       uint8_t userMetadata[remainder()];
   } :remainder()*8;
        
   struct userMetadataOptionValue_t
   {
       uint8_t userMetadata[remainder()];
   } :remainder()*8;
        

The user associates application-defined metadata with each flow. The metadata does not change over the life of the flow. Every flow MUST have metadata. A flow sender MUST send this option with the first User Data chunk for this flow in each packet until an acknowledgement for this flow is received. A flow sender SHOULD NOT send this option more than once for each flow in any one packet. A flow sender SHOULD NOT send this option for a flow once the flow has been acknowledged.

用户将应用程序定义的元数据与每个流相关联。元数据在流的生命周期内不会更改。每个流都必须有元数据。流发送方必须在每个数据包中发送此选项和此流的第一个用户数据块,直到收到此流的确认。对于任何一个数据包中的每个流,流发送方不应多次发送此选项。一旦流被确认,流发送器就不应该为流发送此选项。

This specification doesn't mandate the encoding, syntax, or interpretation of the user's per-flow metadata; this is determined by the application.

本规范不要求对用户的每流元数据进行编码、语法或解释;这由应用程序决定。

The userMetadata SHOULD NOT exceed 512 bytes. The userMetadata MAY be 0 bytes in length.

userMetadata不应超过512字节。userMetadata的长度可能为0字节。

2.3.11.1.2. Return Flow Association
2.3.11.1.2. 回流关联

A new flow can be considered to be in return (or response) to a flow sent by the other endpoint. This option encodes the receive flow identifier to which this new sending flow is a response.

一个新的流可以被认为是对另一个端点发送的流的返回(或响应)。此选项对接收流标识符进行编码,此新发送流是对该标识符的响应。

   +-------------/-+-------------/-+-------------/-+
   |   length    \ |     0x0a    \ |    flowID   \ |
   +-------------/-+-------------/-+-------------/-+
        
   +-------------/-+-------------/-+-------------/-+
   |   length    \ |     0x0a    \ |    flowID   \ |
   +-------------/-+-------------/-+-------------/-+
        
   struct returnFlowAssociationOptionValue_t
   {
       vlu_t flowID :variable*8;
   } :variable*8;
        
   struct returnFlowAssociationOptionValue_t
   {
       vlu_t flowID :variable*8;
   } :variable*8;
        

Consider endpoints A and B. Endpoint A begins a flow with identifier 5 to endpoint B. A is the flow sender for A's flowID=5, and B is the flow receiver for A's flowID=5. B begins a return flow with identifier 7 to A in response to A's flowID=5. B is the flow sender for B's flowID=7, and A is the flow receiver for B's flowID=7. B sends this option with flowID set to 5 to indicate that B's flowID=7 is in response to and associated with A's flowID=5.

Consider endpoints A and B. Endpoint A begins a flow with identifier 5 to endpoint B. A is the flow sender for A's flowID=5, and B is the flow receiver for A's flowID=5. B begins a return flow with identifier 7 to A in response to A's flowID=5. B is the flow sender for B's flowID=7, and A is the flow receiver for B's flowID=7. B sends this option with flowID set to 5 to indicate that B's flowID=7 is in response to and associated with A's flowID=5.translate error, please retry

If there is a return association, the flow sender MUST send this option with the first User Data chunk for this flow in each packet until an acknowledgement for this flow is received. A flow sender SHOULD NOT send this option more than once for each flow in any one packet. A flow sender SHOULD NOT send this option for a flow once the flow has been acknowledged.

如果存在返回关联,则流发送方必须将此选项与每个数据包中此流的第一个用户数据块一起发送,直到收到此流的确认。对于任何一个数据包中的每个流,流发送方不应多次发送此选项。一旦流被确认,流发送器就不应该为流发送此选项。

A flow MUST NOT indicate more than one return association.

一个流不能指示多个返回关联。

A flow MUST indicate its return association, if any, upon its first transmission of a User Data chunk. A return association can't be added to a sending flow after it begins.

流必须在第一次传输用户数据块时指示其返回关联(如果有)。返回关联开始后无法添加到发送流。

A flow receiver MUST reject a new receiving flow having a return flow association that does not indicate an F_OPEN sending flow.

流接收器必须拒绝具有返回流关联的新接收流,该返回流关联不表示F_开放发送流。

2.3.12. Next User Data Chunk
2.3.12. 下一个用户数据块

This chunk is equivalent to the User Data chunk for purposes of sending the user messages of a flow. When used, it MUST follow a User Data chunk or another Next User Data chunk in the same packet.

为了发送流的用户消息,此区块相当于用户数据区块。使用时,它必须跟在同一数据包中的一个用户数据块或另一个下一个用户数据块之后。

    0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |      0x11     |          chunkLength          |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   +-+-+-+-+-+-+-+-+
   |O|r| F | r |A|F|
   |P|s| R | s |B|I|
   |T|v| A | v |N|N|
   +-+-+-+-+-+-+-+-+
   +~~~/~~~/~~~~~~~+               +~~~/~~~/~~~~~~~+-------------/-+
   | L \ T \   V   |... options ...| L \ T \   V   |       0     \ |
   \~~~/~~~/~~~~~~~+   [if(OPT)]   +~~~/~~~/~~~~~~~+-------------/-/
   +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+
   |                            userData                           |
   +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~/
        
    0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |      0x11     |          chunkLength          |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   +-+-+-+-+-+-+-+-+
   |O|r| F | r |A|F|
   |P|s| R | s |B|I|
   |T|v| A | v |N|N|
   +-+-+-+-+-+-+-+-+
   +~~~/~~~/~~~~~~~+               +~~~/~~~/~~~~~~~+-------------/-+
   | L \ T \   V   |... options ...| L \ T \   V   |       0     \ |
   \~~~/~~~/~~~~~~~+   [if(OPT)]   +~~~/~~~/~~~~~~~+-------------/-/
   +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+
   |                            userData                           |
   +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~/
        
   struct nextUserDataChunkPayload_t
   {
       bool_t  optionsPresent :1;  // "OPT"
       uintn_t reserved1 :1;       // "rsv"
       uintn_t fragmentControl :2; // "FRA"
           // 0=whole, 1=begin, 2=end, 3=middle
       uintn_t reserved2 :2;       // "rsv"
       bool_t  abandon :1;         // "ABN"
       bool_t  final :1;           // "FIN"
       if(optionsPresent)
           optionList_t options :variable*8;
       uint8_t userData[remainder()];
   } :chunkLength*8;
        
   struct nextUserDataChunkPayload_t
   {
       bool_t  optionsPresent :1;  // "OPT"
       uintn_t reserved1 :1;       // "rsv"
       uintn_t fragmentControl :2; // "FRA"
           // 0=whole, 1=begin, 2=end, 3=middle
       uintn_t reserved2 :2;       // "rsv"
       bool_t  abandon :1;         // "ABN"
       bool_t  final :1;           // "FIN"
       if(optionsPresent)
           optionList_t options :variable*8;
       uint8_t userData[remainder()];
   } :chunkLength*8;
        

This chunk is considered to be for the same flowID as the most recently preceding User Data or Next User Data chunk in the same packet, having the same Forward Sequence Number, and having the next sequence number. The optionsPresent, fragmentControl, abandon, and final flags, and the options (if present), have the same interpretation as for the User Data chunk.

该区块被认为与同一数据包中最近的前一个用户数据或下一个用户数据区块具有相同的flowID,具有相同的前向序列号和下一个序列号。选项present、fragmentControl、放弃和final标志以及选项(如果存在)的解释与用户数据块的解释相同。

               ...
               ----------+------------------------------------
               10 00 07  | User Data chunk, length=7
               00        | OPT=0, FRA=0 "whole", ABN=0, FIN=0
               02 05 03  | flowID=2, seq#=5, fsn=(5-3)=2
               00 01 02  | data 3 bytes: 00, 01, 02
               ----------+------------------------------------
               11 00 04  | Next User Data chunk,length=4
               00        | OPT=0, FRA=0 "whole", ABN=0, FIN=0
                         | flowID=2, seq#=6, fsn=2
               03 04 05  | data 3 bytes: 03, 04, 05
               ----------+------------------------------------
               11 00 04  | Next User Data chunk, length=4
               00        | OPT=0, FRA=0 "whole", ABN=0, FIN=0
                         | flowID=2, seq#=7, fsn=2
               06 07 08  | data 3 bytes: 06, 07, 08
               ----------+------------------------------------
        
               ...
               ----------+------------------------------------
               10 00 07  | User Data chunk, length=7
               00        | OPT=0, FRA=0 "whole", ABN=0, FIN=0
               02 05 03  | flowID=2, seq#=5, fsn=(5-3)=2
               00 01 02  | data 3 bytes: 00, 01, 02
               ----------+------------------------------------
               11 00 04  | Next User Data chunk,length=4
               00        | OPT=0, FRA=0 "whole", ABN=0, FIN=0
                         | flowID=2, seq#=6, fsn=2
               03 04 05  | data 3 bytes: 03, 04, 05
               ----------+------------------------------------
               11 00 04  | Next User Data chunk, length=4
               00        | OPT=0, FRA=0 "whole", ABN=0, FIN=0
                         | flowID=2, seq#=7, fsn=2
               06 07 08  | data 3 bytes: 06, 07, 08
               ----------+------------------------------------
        

Figure 3: Sequential Messages in One Packet Using Next User Data

图3:使用下一个用户数据的一个数据包中的顺序消息

The use of Next User Data is detailed in Section 3.6.2.3.2.

第3.6.2.3.2节详细说明了下一个用户数据的使用。

2.3.13. Data Acknowledgement Bitmap Chunk (Bitmap Ack)
2.3.13. 数据确认位图块(位图确认)

This chunk is sent by the flow receiver to indicate to the flow sender the User Data fragment sequence numbers that have been received for one flow. It is only allowed in a packet belonging to an established session and having packet mode 1 or 2.

此区块由流接收器发送,以向流发送器指示已接收到的一个流的用户数据片段序列号。它仅允许在属于已建立会话且具有分组模式1或2的分组中使用。

The flow receiver can choose to acknowledge User Data with this chunk or with a Range Ack. It SHOULD choose whichever format has the most compact encoding of the sequence numbers received.

流接收器可以选择使用此数据块或范围Ack确认用户数据。它应该选择接收到的序列号编码最紧凑的格式。

    0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |      0x50     |          chunkLength          |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   +-------------/-+-------------/-+-------------/-+
   |   flowID    \ |   bufAvail  \ |    cumAck   \ |
   +-------------/-+-------------/-+-------------/-+
   +~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+
   |C|C|C|C|C|C|C|C|C|C|C|C|C|C|C|C|C|C|C|C|C|C|C|C|
   |+|+|+|+|+|+|+|+|+|+|+|+|+|+|+|+|+|+|+|+|+|+|+|+|
   |9|8|7|6|5|4|3|2|1|1|1|1|1|1|1|1|2|2|2|2|2|2|1|1| ....
   | | | | | | | | |7|6|5|4|3|2|1|0|5|4|3|2|1|0|9|8|
   +~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+
        
    0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |      0x50     |          chunkLength          |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   +-------------/-+-------------/-+-------------/-+
   |   flowID    \ |   bufAvail  \ |    cumAck   \ |
   +-------------/-+-------------/-+-------------/-+
   +~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+
   |C|C|C|C|C|C|C|C|C|C|C|C|C|C|C|C|C|C|C|C|C|C|C|C|
   |+|+|+|+|+|+|+|+|+|+|+|+|+|+|+|+|+|+|+|+|+|+|+|+|
   |9|8|7|6|5|4|3|2|1|1|1|1|1|1|1|1|2|2|2|2|2|2|1|1| ....
   | | | | | | | | |7|6|5|4|3|2|1|0|5|4|3|2|1|0|9|8|
   +~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+
        
   struct dataAckBitmapChunkPayload_t
   {
       vlu_t flowID :variable*8;
       vlu_t bufferBlocksAvailable :variable*8; // "bufAvail"
       vlu_t cumulativeAck :variable*8; // "cumAck"
       bufferBytesAvailable = bufferBlocksAvailable * 1024;
       acknowledge(0 through cumulativeAck);
       ackCursor = cumulativeAck + 1;
       while(remainder() > 0)
       {
           for(bitPosition = 8; bitPosition > 0; bitPosition--)
           {
               bool_t bit :1;
               if(bit)
                   acknowledge(ackCursor + bitPosition);
           }
           ackCursor += 8;
       }
   } :chunkLength*8;
        
   struct dataAckBitmapChunkPayload_t
   {
       vlu_t flowID :variable*8;
       vlu_t bufferBlocksAvailable :variable*8; // "bufAvail"
       vlu_t cumulativeAck :variable*8; // "cumAck"
       bufferBytesAvailable = bufferBlocksAvailable * 1024;
       acknowledge(0 through cumulativeAck);
       ackCursor = cumulativeAck + 1;
       while(remainder() > 0)
       {
           for(bitPosition = 8; bitPosition > 0; bitPosition--)
           {
               bool_t bit :1;
               if(bit)
                   acknowledge(ackCursor + bitPosition);
           }
           ackCursor += 8;
       }
   } :chunkLength*8;
        

flowID: VLU, the flow identifier.

flowID:VLU,流标识符。

bufferBlocksAvailable: VLU, the number of 1024-byte blocks of User Data that the receiver is currently able to accept. Section 3.6.3.5 describes how to calculate this value.

bufferBlocksAvailable:VLU,接收器当前能够接受的1024字节用户数据块数。第3.6.3.5节描述了如何计算该值。

cumulativeAck: VLU, the acknowledgement of every fragment sequence number in this flow that is less than or equal to this value. This MUST NOT be less than the highest Forward Sequence Number received in this flow.

cumulativeAck:VLU,此流中小于或等于此值的每个片段序列号的确认。这不得小于此流中接收到的最高转发序列号。

bit field: A sequence of zero or more bytes representing a bit field of received fragment sequence numbers after the cumulative acknowledgement, least significant bit first. A set bit indicates receipt of a sequence number. A clear bit indicates that sequence number was not received. The least significant bit of the first byte is the second sequence number following the cumulative acknowledgement, the next bit is the third sequence number following, and so on.

位字段:一个零字节或更多字节的序列,表示在累积确认之后接收到的片段序列号的位字段,最低有效位优先。设定位表示接收序列号。清除位表示未收到序列号。第一个字节的最低有效位是累积确认后的第二个序列号,下一位是累积确认后的第三个序列号,依此类推。

Figure 4 shows an example Bitmap Ack indicating acknowledgement of fragment sequence numbers 0 through 16, 18, 21 through 24, 27, and 28.

图4显示了一个示例位图Ack,指示确认片段序列号0到16、18、21到24、27和28。

         50 00 05  | Bitmap Ack, length=5 bytes
         05 7f 10  | flowID=5, bufAvail=127*1024 bytes, cumAck=0..16
         79 06     | 01111001 00000110 = 18, 21, 22, 23, 24, 27, 28
        
         50 00 05  | Bitmap Ack, length=5 bytes
         05 7f 10  | flowID=5, bufAvail=127*1024 bytes, cumAck=0..16
         79 06     | 01111001 00000110 = 18, 21, 22, 23, 24, 27, 28
        

Figure 4: Example Bitmap Ack

图4:位图确认示例

2.3.14. Data Acknowledgement Ranges Chunk (Range Ack)
2.3.14. 数据确认范围块(范围确认)

This chunk is sent by the flow receiver to indicate to the flow sender the User Data fragment sequence numbers that have been received for one flow. It is only allowed in a packet belonging to an established session and having packet mode 1 or 2.

此区块由流接收器发送,以向流发送器指示已接收到的一个流的用户数据片段序列号。它仅允许在属于已建立会话且具有分组模式1或2的分组中使用。

The flow receiver can choose to acknowledge User Data with this chunk or with a Bitmap Ack. It SHOULD choose whichever format has the most compact encoding of the sequence numbers received.

流接收器可以选择使用此数据块或位图Ack确认用户数据。它应该选择接收到的序列号编码最紧凑的格式。

    0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |      0x51     |          chunkLength          |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   +-------------/-+-------------/-+-------------/-+
   |   flowID    \ |   bufAvail  \ |    cumAck   \ |
   +-------------/-+-------------/-+-------------/-+
   +~~~~~~~~~~~~~/~+~~~~~~~~~~~~~/~+
   |   #holes-1  \ |   #recv-1   \ |
   +~~~~~~~~~~~~~/~+~~~~~~~~~~~~~/~+
                   :
                   :
   +~~~~~~~~~~~~~/~+~~~~~~~~~~~~~/~+
   |   #holes-1  \ |   #recv-1   \ |
   +~~~~~~~~~~~~~/~+~~~~~~~~~~~~~/~+
        
    0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |      0x51     |          chunkLength          |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   +-------------/-+-------------/-+-------------/-+
   |   flowID    \ |   bufAvail  \ |    cumAck   \ |
   +-------------/-+-------------/-+-------------/-+
   +~~~~~~~~~~~~~/~+~~~~~~~~~~~~~/~+
   |   #holes-1  \ |   #recv-1   \ |
   +~~~~~~~~~~~~~/~+~~~~~~~~~~~~~/~+
                   :
                   :
   +~~~~~~~~~~~~~/~+~~~~~~~~~~~~~/~+
   |   #holes-1  \ |   #recv-1   \ |
   +~~~~~~~~~~~~~/~+~~~~~~~~~~~~~/~+
        
   struct dataAckRangesChunkPayload_t
   {
       vlu_t flowID :variable*8;
       vlu_t bufferBlocksAvailable :variable*8; // "bufAvail"
       vlu_t cumulativeAck :variable*8; // "cumAck"
       bufferBytesAvailable = bufferBlocksAvailable * 1024;
       acknowledge(0 through cumulativeAck);
       ackCursor = cumulativeAck;
       while(remainder() > 0)
       {
           vlu_t holesMinusOne :variable*8; // "#holes-1"
           vlu_t receivedMinusOne :variable*8; // "#recv-1"
        
   struct dataAckRangesChunkPayload_t
   {
       vlu_t flowID :variable*8;
       vlu_t bufferBlocksAvailable :variable*8; // "bufAvail"
       vlu_t cumulativeAck :variable*8; // "cumAck"
       bufferBytesAvailable = bufferBlocksAvailable * 1024;
       acknowledge(0 through cumulativeAck);
       ackCursor = cumulativeAck;
       while(remainder() > 0)
       {
           vlu_t holesMinusOne :variable*8; // "#holes-1"
           vlu_t receivedMinusOne :variable*8; // "#recv-1"
        
           ackCursor++;
           rangeFrom = ackCursor + holesMinusOne + 1;
           rangeTo = rangeFrom + receivedMinusOne;
           acknowledge(rangeFrom through rangeTo);
        
           ackCursor++;
           rangeFrom = ackCursor + holesMinusOne + 1;
           rangeTo = rangeFrom + receivedMinusOne;
           acknowledge(rangeFrom through rangeTo);
        
           ackCursor = rangeTo;
       }
   } :chunkLength*8;
        
           ackCursor = rangeTo;
       }
   } :chunkLength*8;
        

flowID: VLU, the flow identifier.

flowID:VLU,流标识符。

bufferBlocksAvailable: VLU, the number of 1024-byte blocks of User Data that the receiver is currently able to accept. Section 3.6.3.5 describes how to calculate this value.

bufferBlocksAvailable:VLU,接收器当前能够接受的1024字节用户数据块数。第3.6.3.5节描述了如何计算该值。

cumulativeAck: VLU, the acknowledgement of every fragment sequence number in this flow that is less than or equal to this value. This MUST NOT be less than the highest Forward Sequence Number received in this flow.

cumulativeAck:VLU,此流中小于或等于此值的每个片段序列号的确认。这不得小于此流中接收到的最高转发序列号。

holesMinusOne / receivedMinusOne: Zero or more acknowledgement ranges, run-length encoded. Runs are encoded as zero or more pairs of VLUs indicating the number (minus one) of missing sequence numbers followed by the number (minus one) of received sequence numbers, starting at the cumulative acknowledgement. NOTE: If a parser syntax error is encountered here (that is, if the chunk is truncated such that not enough bytes remain to completely encode both VLUs of the acknowledgement range), then treat and process this chunk as though it was properly formed up to the last completely encoded range.

holesMinusOne/receivedMinusOne:零个或多个确认范围,运行长度编码。从累积确认开始,运行被编码为零对或多对VLU,指示缺失序列号的数量(减1),然后是接收序列号的数量(减1)。注意:如果在这里遇到解析器语法错误(即,如果区块被截断,以至于没有足够的字节来完全编码确认范围的两个VLU),则将该区块视为正确形成到最后一个完全编码的范围,并对其进行处理。

Figure 5 shows an example Range Ack indicating acknowledgement of fragment sequence numbers 0 through 16, 18, 21, 22, 23, and 24.

图5显示了一个示例范围Ack,该范围指示确认片段序列号0到16、18、21、22、23和24。

      51 00 07  | Range Ack, length=7
      05 7f 10  | flowID=5, bufAvail=127*1024 bytes, cumAck=0..16
      00 00     | holes=1, received=1 -- missing 17, received 18
      01 03     | holes=2, received=4 -- missing 19..20, received 21..24
        
      51 00 07  | Range Ack, length=7
      05 7f 10  | flowID=5, bufAvail=127*1024 bytes, cumAck=0..16
      00 00     | holes=1, received=1 -- missing 17, received 18
      01 03     | holes=2, received=4 -- missing 19..20, received 21..24
        

Figure 5: Example Range Ack

图5:范围确认示例

Figure 6 shows an example Range Ack indicating acknowledgement of fragment sequence numbers 0 through 16 and 18, with a truncated last range. Note that the truncation and parse error does not abort the entire chunk in this case.

图6显示了一个示例范围Ack,表示确认片段序列号0到16和18,最后一个范围被截断。请注意,在这种情况下,截断和解析错误不会中止整个区块。

       51 00 07  | Range Ack, length=9
       05 7f 10  | flowID=5, bufAvail=127*1024 bytes, cumAck=0..16
       00 00     | holes=1, received=1 -- missing 17, received 18
       01 83     | holes=2, received=VLU parse error, ignore this range
        
       51 00 07  | Range Ack, length=9
       05 7f 10  | flowID=5, bufAvail=127*1024 bytes, cumAck=0..16
       00 00     | holes=1, received=1 -- missing 17, received 18
       01 83     | holes=2, received=VLU parse error, ignore this range
        

Figure 6: Example Truncated Range Ack

图6:截短范围Ack示例

2.3.15. Buffer Probe Chunk
2.3.15. 缓冲区探测块

This chunk is sent by the flow sender in order to request the current available receive buffer (in the form of a Data Acknowledgement) for a flow. It is only allowed in a packet belonging to an established session and having packet mode 1 or 2.

此区块由流发送器发送,以请求流的当前可用接收缓冲区(以数据确认的形式)。它仅允许在属于已建立会话且具有分组模式1或2的分组中使用。

    0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |      0x18     |          chunkLength          |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   +-------------/-+
   |   flowID    \ |
   +-------------/-+
        
    0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |      0x18     |          chunkLength          |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   +-------------/-+
   |   flowID    \ |
   +-------------/-+
        
   struct bufferProbeChunkPayload_t
   {
       vlu_t flowID :variable*8;
   } :chunkLength*8;
        
   struct bufferProbeChunkPayload_t
   {
       vlu_t flowID :variable*8;
   } :chunkLength*8;
        

flowID: VLU, the flow identifier.

flowID:VLU,流标识符。

The receiver of this chunk SHOULD reply as immediately as is practical with a Data Acknowledgement.

此数据块的接收者应立即回复数据确认。

2.3.16. Flow Exception Report Chunk
2.3.16. 流异常报告块

This chunk is sent by the flow receiver to indicate that it is not (or is no longer) interested in the flow and would like the flow sender to close the flow. This chunk SHOULD precede every Data Acknowledgement chunk for the same flow in this condition.

此区块由流接收器发送,以指示它对流不感兴趣(或不再感兴趣),并希望流发送器关闭流。在这种情况下,对于相同的流,该块应该位于每个数据确认块之前。

This chunk is only allowed in a packet belonging to an established session and having packet mode 1 or 2.

此区块仅允许存在于属于已建立会话且具有数据包模式1或2的数据包中。

    0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |      0x5e     |          chunkLength          |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   +-------------/-+-------------/-+
   |   flowID    \ |  exception  \ |
   +-------------/-+-------------/-+
        
    0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |      0x5e     |          chunkLength          |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   +-------------/-+-------------/-+
   |   flowID    \ |  exception  \ |
   +-------------/-+-------------/-+
        
   struct flowExceptionReportChunkPayload_t
   {
       vlu_t flowID :variable*8;
       vlu_t exception :variable*8;
   } :chunkLength*8;
        
   struct flowExceptionReportChunkPayload_t
   {
       vlu_t flowID :variable*8;
       vlu_t exception :variable*8;
   } :chunkLength*8;
        

flowID: VLU, the flow identifier.

flowID:VLU,流标识符。

exception: VLU, the application-defined exception code being reported.

异常:VLU,报告的应用程序定义的异常代码。

A receiving RTMFP might reject a flow automatically, for example if it is missing metadata, or if an invalid return association is specified. In circumstances where an RTMFP rejects a flow automatically, the exception code MUST be 0. The application can specify any exception code, including 0, when rejecting a flow. All non-zero exception codes are reserved for the application.

接收RTMFP可能会自动拒绝流,例如,如果流缺少元数据,或者指定了无效的返回关联。在RTMFP自动拒绝流的情况下,异常代码必须为0。拒绝流时,应用程序可以指定任何异常代码,包括0。所有非零异常代码都保留给应用程序。

2.3.17. Session Close Request Chunk (Close)
2.3.17. 会话关闭请求块(关闭)

This chunk is sent to cleanly terminate a session. It is only allowed in a packet belonging to an established or closing session and having packet mode 1 or 2.

发送此区块是为了干净地终止会话。仅允许在属于已建立或关闭会话且具有数据包模式1或2的数据包中使用。

    0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |      0x0c     |               0               |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
        
    0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |      0x0c     |               0               |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
        

This chunk has no payload.

此块没有有效负载。

The use of Close is detailed in Section 3.5.5.

第3.5.5节详细介绍了Close的使用。

2.3.18. Session Close Acknowledgement Chunk (Close Ack)
2.3.18. 会话关闭确认块(关闭确认)

This chunk is sent in response to a Session Close Request to indicate that the sender has terminated the session. It is only allowed in a packet belonging to an established or closing session and having packet mode 1 or 2.

发送此区块是为了响应会话关闭请求,以指示发送方已终止会话。仅允许在属于已建立或关闭会话且具有数据包模式1或2的数据包中使用。

    0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |      0x4c     |               0               |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
        
    0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |      0x4c     |               0               |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
        

This chunk has no payload.

此块没有有效负载。

The use of Close Ack is detailed in Section 3.5.5.

第3.5.5节详细说明了闭合Ack的使用。

3. Operation
3. 活动
3.1. Overview
3.1. 概述
              +--------+                             +--------+
              | Peer A |        S E S S I O N        | Peer B |
              |        /=============================\        |
              |       ||            Flows            ||       |
              |       ||---------------------------->||       |
              |       ||---------------------------->||       |
              |       ||<----------------------------||       |
              |       ||<----------------------------||       |
              |       ||<----------------------------||       |
              |        \=============================/        |
              |        |                             |        |
              |        |                             +--------+
              |        |
              |        |                             +--------+
              |        |        S E S S I O N        | Peer C |
              |        /=============================\        |
              |       ||            Flows            ||       |
              |       ||---------------------------->||       |
              |       ||<----------------------------||       |
              |       ||<----------------------------||       |
              |        \=============================/        |
              |        |                             |        |
              +--------+                             +--------+
        
              +--------+                             +--------+
              | Peer A |        S E S S I O N        | Peer B |
              |        /=============================\        |
              |       ||            Flows            ||       |
              |       ||---------------------------->||       |
              |       ||---------------------------->||       |
              |       ||<----------------------------||       |
              |       ||<----------------------------||       |
              |       ||<----------------------------||       |
              |        \=============================/        |
              |        |                             |        |
              |        |                             +--------+
              |        |
              |        |                             +--------+
              |        |        S E S S I O N        | Peer C |
              |        /=============================\        |
              |       ||            Flows            ||       |
              |       ||---------------------------->||       |
              |       ||<----------------------------||       |
              |       ||<----------------------------||       |
              |        \=============================/        |
              |        |                             |        |
              +--------+                             +--------+
        

Figure 7: Sessions between Pairs of Communicating Endpoints

图7:通信端点对之间的会话

Between any pair of communicating endpoints is a single, bidirectional, secured, congestion controlled session. Unidirectional flows convey messages from one end to the other within the session.

在任何一对通信端点之间是一个单一的、双向的、安全的、拥塞控制的会话。单向流在会话内将消息从一端传递到另一端。

An endpoint initiates a session to a far end when communication is desired. An initiator begins with one or more candidate destination socket addresses, and it may learn and try more candidate addresses during startup handshaking. Eventually, a first suitable response is received, and that endpoint is selected. Startup proceeds to the selected endpoint. In the case of session startup glare, one endpoint is the prevailing initiator and the other assumes the role of responder. Encryption keys and session identifiers are negotiated between the endpoints, and the session is established.

当需要通信时,端点向远端发起会话。启动器从一个或多个候选目标套接字地址开始,在启动握手过程中,它可能会学习并尝试更多候选地址。最终,接收到第一个合适的响应,并选择该端点。启动继续到选定的端点。在会话启动眩光的情况下,一个端点是主要的发起方,另一个端点承担响应方的角色。在端点之间协商加密密钥和会话标识符,并建立会话。

Each endpoint may begin sending message flows to the other end. For each flow, the far end may accept it and deliver its messages to the user, or it may reject the flow and transmit an exception to the

每个端点可以开始向另一端发送消息流。对于每个流,远端可以接受该流并将其消息传递给用户,也可以拒绝该流并将异常发送给用户

sender. The flow receiver may close and reject a flow at a later time, after first accepting it. The flow receiver acknowledges all data sent to it, regardless of whether the flow was accepted. Acknowledgements drive a congestion control mechanism.

发件人。流量接收器可在首次接受流量后的稍后时间关闭并拒绝该流量。流接收器确认发送给它的所有数据,无论流是否被接受。确认驱动拥塞控制机制。

An endpoint may have concurrent sessions with other far endpoints. The multiple sessions are distinguished by a session identifier rather than by socket address. This allows an endpoint's address to change mid-session without having to tear down and re-establish a session. The existing cryptographic state for a session can be used to verify a change of address while protecting against session hijacking or denial of service.

端点可能与其他远端端点具有并发会话。多个会话通过会话标识符而不是套接字地址来区分。这允许端点的地址在会话中期更改,而无需中断和重新建立会话。会话的现有加密状态可用于验证地址更改,同时防止会话劫持或拒绝服务。

A sender may indicate to a receiver that some user messages are of a time critical or real-time nature. A receiver may indicate to senders on concurrent sessions that it is receiving time critical messages from another endpoint. The other senders SHOULD modify their congestion control parameters to yield capacity to the session carrying time critical messages.

发送方可向接收方指示某些用户消息具有时间关键性或实时性。接收方可以在并发会话上向发送方指示它正在从另一个端点接收时间关键的消息。其他发送方应修改其拥塞控制参数,以便为承载时间关键型消息的会话提供容量。

A sender may close a flow. The flow is completed when the receiver has no outstanding gaps before the final fragment of the flow. The sender and receiver reserve a completed flow's identifier for a time to allow in-flight messages to drain from the network.

发送方可以关闭流。当接收器在流的最终片段之前没有未完成的间隙时,流完成。发送方和接收方在一段时间内保留一个完整流的标识符,以允许飞行中的消息从网络中排出。

Eventually, neither end will have any flows open to the other. The session will be idle and quiescent. Either end may reliably close the session to recover its resources.

最终,任何一端都不会向另一端开放任何流。会话将处于空闲和静止状态。任何一端都可以可靠地关闭会话以恢复其资源。

In certain circumstances, an endpoint may be ceasing operation and not have time to wait for acknowledgement of a reliable session close. In this case, the halting endpoint may send an abrupt session close to advise the far end that it is halting immediately.

在某些情况下,端点可能正在停止操作,没有时间等待可靠会话关闭的确认。在这种情况下,停止端点可以发送一个突然的会话close,以通知远端它正在立即停止。

3.2. Endpoint Identity
3.2. 端点标识

Each RTMFP endpoint has an identity. The identity is encoded in a certificate. This specification doesn't mandate any particular certificate format, cryptographic algorithms, or cryptographic properties for certificates.

每个RTMFP端点都有一个标识。身份编码在证书中。本规范不强制要求证书使用任何特定的证书格式、加密算法或加密属性。

An endpoint is named by an Endpoint Discriminator. This specification doesn't mandate any particular format for Endpoint Discriminators.

端点由端点鉴别器命名。本规范不要求端点鉴别器使用任何特定格式。

An Endpoint Discriminator MAY select more than one identity and MAY match more than one distinct certificate.

端点鉴别器可以选择多个标识,并且可以匹配多个不同的证书。

Multiple distinct Endpoint Discriminators MAY match one certificate.

多个不同的端点鉴别器可能与一个证书匹配。

It is RECOMMENDED that multiple endpoints not have the same identity. Entities with the same identity are indistinguishable during session startup; this situation could be undesirable in some applications.

建议多个端点不具有相同的标识。会话启动期间,具有相同标识的实体无法区分;这种情况在某些应用中可能是不可取的。

An endpoint MAY have more than one address.

端点可以有多个地址。

The Cryptography Profile implements the following functions for identities, certificates, and Endpoint Discriminators, whose operation MUST be deterministic:

加密配置文件为身份、证书和端点鉴别器实现以下功能,这些鉴别器的操作必须是确定性的:

o Test whether a given certificate is authentic. Authenticity can comprise verifying an issuer signature chain in a public key infrastructure.

o 测试给定的证书是否真实。真实性可以包括验证公钥基础设施中的颁发者签名链。

o Test whether a given Endpoint Discriminator selects a given certificate.

o 测试给定端点鉴别器是否选择给定证书。

o Test whether a given Endpoint Discriminator selects the local endpoint.

o 测试给定端点鉴别器是否选择本地端点。

o Generate a Canonical Endpoint Discriminator for a given certificate. Canonical Endpoint Discriminators for distinct identities SHOULD be distinct. If two distinct identities have the same Canonical Endpoint Discriminator, an initiator might abort a new opening session to the second identity (Section 3.5.1.1.1); this behavior might not be desirable.

o 为给定证书生成规范端点鉴别器。不同身份的规范端点鉴别器应该是不同的。如果两个不同的标识具有相同的规范端点鉴别器,则启动器可能会中止第二个标识的新打开会话(第3.5.1.1.1节);这种行为可能不可取。

o Given a certificate, a message, and a digital signature over the message, test whether the signature is valid and generated by the owner of the certificate.

o 给定证书、消息和消息上的数字签名,测试签名是否有效并由证书所有者生成。

o Generate a digital signature for a given message corresponding to the near identity.

o 为与近身份对应的给定消息生成数字签名。

o Given the near identity and a far certificate, determine which one shall prevail as Initiator and which shall assume the Responder role in the case of startup glare. The far end MUST arrive at the same conclusion. A comparison function can comprise performing a lexicographic ordering of the binary certificates, declaring the far identity the prevailing endpoint if the far certificate is ordered before the near certificate, and otherwise declaring the near identity to be the prevailing endpoint.

o 考虑到近身份和远身份证书,确定在启动眩光的情况下,哪一个应作为发起人,哪一个应承担响应者的角色。远端必须得出相同的结论。比较函数可以包括执行二进制证书的字典排序,如果远证书排序在近证书之前,则将远标识声明为主要端点,否则将近标识声明为主要端点。

o Given a first certificate and a second certificate, test whether a new incoming session from the second shall override an existing session with the first. It is RECOMMENDED that the test comprise testing whether the certificates are bitwise identical.

o 给定第一个证书和第二个证书,测试来自第二个证书的新传入会话是否应使用第一个证书覆盖现有会话。建议测试包括测试证书是否按位相同。

All other semantics for certificates and Endpoint Discriminators are determined by the Cryptography Profile and the application.

证书和端点鉴别器的所有其他语义由加密配置文件和应用程序确定。

3.3. Packet Multiplex
3.3. 分组多路复用

An RTMFP typically has one or more interfaces through which it communicates with other RTMFP endpoints. RTMFP can communicate with multiple distinct other RTMFP endpoints through each local interface. Session multiplexing over a shared interface can facilitate peer-to-peer communications through a NAT, by enabling third-party endpoints such as Forwarders (Section 3.5.1.5) and Redirectors (Section 3.5.1.4) to observe the translated public address and inform peers of the translation.

RTMFP通常具有一个或多个接口,通过这些接口与其他RTMFP端点进行通信。RTMFP可以通过每个本地接口与多个不同的其他RTMFP端点通信。通过共享接口上的会话多路复用可以通过NAT促进对等通信,方法是启用第三方端点,如转发器(第3.5.1.5节)和重定向器(第3.5.1.4节),以观察翻译后的公共地址并将翻译通知对等方。

An interface is typically a UDP socket (Section 2.2.1) but MAY be any suitable datagram transport service where endpoints can be addressed by IPv4 or IPv6 socket addresses.

接口通常是UDP套接字(第2.2.1节),但也可以是任何合适的数据报传输服务,其中端点可以通过IPv4或IPv6套接字地址寻址。

RTMFP uses a session ID to multiplex and demultiplex communications with distinct endpoints (Section 2.2.2), in addition to the endpoint socket address. This allows an RTMFP to detect a far-end address change (as might happen, for example, in mobile and wireless scenarios) and allows communication sessions to survive address changes. This also allows an RTMFP to act as a Forwarder or Redirector for an endpoint with which it has an active session, by distinguishing startup packets from those of the active session.

除了端点套接字地址外,RTMFP还使用会话ID来多路复用和解多路复用与不同端点的通信(第2.2.2节)。这允许RTMFP检测远端地址更改(例如,在移动和无线场景中可能发生的情况),并允许通信会话在地址更改后继续存在。这还允许RTMFP通过区分启动数据包和活动会话的启动数据包,充当具有活动会话的端点的转发器或重定向器。

On receiving a packet, an RTMFP decodes the session ID to look up the corresponding session information context and decryption key. Session ID 0 is reserved for session startup and MUST NOT be used for an active session. A packet for Session ID 0 uses the Default Session Key as defined by the Cryptography Profile.

在接收到分组时,RTMFP对会话ID进行解码以查找相应的会话信息上下文和解密密钥。会话ID 0保留用于会话启动,不能用于活动会话。会话ID为0的数据包使用加密配置文件定义的默认会话密钥。

3.4. Packet Fragmentation
3.4. 数据包碎片

When an RTMFP packet (Section 2.2.4) is unavoidably larger than the path MTU (such as a startup packet containing an RHello (Section 2.3.4) or IIKeying (Section 2.3.7) chunk with a large certificate), it can be fragmented into segments that do not exceed the path MTU by using the Packet Fragment chunk (Section 2.3.1).

当RTMFP数据包(第2.2.4节)不可避免地大于路径MTU(例如,包含RHello(第2.3.4节)或具有大证书的IIKeying(第2.3.7节)数据块的启动数据包)时,可以使用数据包片段数据块(第2.3.1节)将其分割为不超过路径MTU的数据段。

The packet fragmentation mechanism SHOULD be used only to segment unavoidably large packets. Accordingly, this mechanism SHOULD be employed only during session startup with Session ID 0. This mechanism MUST NOT be used instead of the natural fragmentation mechanism of the User Data (Section 2.3.11) and Next User Data (Section 2.3.12) chunks for dividing the messages of the user's data flows into segments that do not exceed the path MTU.

数据包分段机制应仅用于分割不可避免的大数据包。因此,此机制应仅在会话ID为0的会话启动期间使用。不得使用该机制代替用户数据(第2.3.11节)和下一个用户数据(第2.3.12节)块的自然分段机制,以将用户数据流的消息划分为不超过路径MTU的段。

A fragmented plain RTMFP packet is reassembled by concatenating the packetFragment fields of the fragments for the packet in contiguous ascending order, starting from index 0 through and including the final fragment.

通过以连续的升序连接数据包片段的packetFragment字段(从索引0开始到包括最终片段),重新组装片段化的普通RTMFP数据包。

When reassembling packets for Session ID 0, a receiver SHOULD identify the packets by the socket address from which the packet containing the fragment was received, as well as the indicated packetID.

当重新组装会话ID为0的数据包时,接收方应通过从中接收包含片段的数据包的套接字地址以及指示的packetID来识别数据包。

A receiver SHOULD allow up to 60 seconds to completely receive a fragmented packet for which progress is being made. A packet is progressing if at least one new fragment for it was received in the last second.

接收器应允许最多60秒的时间完全接收正在进行处理的碎片数据包。如果在最后一秒钟内至少收到一个数据包的新片段,则该数据包正在进行。

A receiver MUST discard a Packet Fragment chunk having an empty packetFragment field.

接收方必须丢弃具有空packetFragment字段的数据包片段块。

The mode of each packet containing Packet Fragments for the same fragmented packet MUST match the mode of the fragmented packet. A receiver MUST discard any new Packet Fragment chunk received in a packet with a mode different from the mode of the packet containing the first received fragment. A receiver MUST discard any reassembled packet with a mode different than the packets containing its fragments.

包含相同碎片数据包的数据包碎片的每个数据包的模式必须与碎片数据包的模式匹配。接收方必须丢弃在模式不同于包含第一个接收片段的数据包模式的数据包中接收的任何新数据包片段块。接收器必须丢弃模式不同于包含其片段的数据包的任何重新组装的数据包。

In order to avoid jamming the network, the sender MUST rate limit packet transmission. In the absence of specific path capacity information (for instance, during session startup), a sender SHOULD NOT send more than 4380 bytes nor more than four packets per distinct endpoint every 200 ms.

为了避免干扰网络,发送方必须限制数据包的传输速率。在缺少特定路径容量信息的情况下(例如,在会话启动期间),发送方不应每200ms向每个不同端点发送超过4380字节或超过四个数据包。

To avoid resource exhaustion, a receiver SHOULD limit the number of concurrent packet reassembly buffers and the size of each buffer. Limits can depend, for example, on the expected size of reassembled packets, on the rate at which fragmented packets are expected to be received, on the expected degree of interleaving, and on the expected function of the receiver. Limits can depend on the available resources of the receiver. There can be different limits for packets with Session ID 0 and packets for established sessions. For example,

为了避免资源耗尽,接收器应该限制并发数据包重组缓冲区的数量和每个缓冲区的大小。例如,限制可以取决于重新组装的分组的预期大小、预期接收分段分组的速率、预期交织程度以及接收机的预期功能。限制可能取决于接收器的可用资源。会话ID为0的数据包和已建立会话的数据包可以有不同的限制。例如

a busy server might need to allow for several hundred concurrent packet reassembly buffers to accommodate hundreds of connection requests per second with potentially interleaved fragments, but a client device with constrained resources could allow just a few reassembly buffers. In the absence of specific information regarding the expected size of reassembled packets, a receiver should set the limit for each packet reassembly buffer to 65536 bytes.

繁忙的服务器可能需要允许数百个并发数据包重组缓冲区,以容纳每秒数百个连接请求(可能是交错的片段),但资源受限的客户端设备可能只允许几个重组缓冲区。在没有关于重新组装数据包的预期大小的具体信息的情况下,接收器应将每个数据包重新组装缓冲区的限制设置为65536字节。

3.5. Sessions
3.5. 会议

A session is the protocol relationship between a pair of communicating endpoints, comprising the shared and endpoint-specific information context necessary to carry out the communication. The session context at each end includes at least:

会话是一对通信端点之间的协议关系,包括执行通信所需的共享和特定于端点的信息上下文。每一端的会话上下文至少包括:

o TS_RX: the last timestamp received from the far end;

o TS_RX:从远端接收的最后一个时间戳;

o TS_RX_TIME: the time at which TS_RX was first observed to be different than its previous value;

o TS_RX_时间:首次观察到TS_RX与其先前值不同的时间;

o TS_ECHO_TX: the last timestamp echo sent to the far end;

o TS_ECHO_TX:发送到远端的最后一个时间戳ECHO;

o MRTO: the measured retransmission timeout;

o MRTO:测量的重传超时;

o ERTO: the effective retransmission timeout;

o ERTO:有效重传超时;

o Cryptographic keys for encrypting and decrypting packets, and for verifying the validity of packets, according to the Cryptography Profile;

o 根据所述密码简档,用于加密和解密分组以及用于验证分组的有效性的密码密钥;

o Cryptographic near and far nonces according to the Cryptography Profile, where the near nonce is the far end's far nonce, and vice versa;

o 根据加密配置文件加密近时值和远时值,其中近时值是远端的远时值,反之亦然;

o The certificate of the far end;

o 远端的证书;

o The receive session identifier, used by the far end when sending packets to this end;

o 接收会话标识符,远端在向该端发送数据包时使用;

o The send session identifier to use when sending packets to the far end;

o 向远端发送分组时要使用的发送会话标识符;

o DESTADDR: the destination socket address to use when sending packets to the far end;

o DESTADDR:向远端发送数据包时要使用的目标套接字地址;

o The set of all sending flow contexts (Section 3.6.2);

o 所有发送流上下文的集合(第3.6.2节);

o The set of all receiving flow contexts (Section 3.6.3);

o 所有接收流上下文的集合(第3.6.3节);

o The transmission budget, which controls the rate at which data is sent into the network (for example, a congestion window);

o 传输预算,控制数据发送到网络的速率(例如,拥塞窗口);

o S_OUTSTANDING_BYTES: the total amount of user message data outstanding, or in flight, in the network -- that is, the sum of the F_OUTSTANDING_BYTES of each sending flow in the session;

o S_未决_字节:网络中未决或正在传输的用户消息数据总量——即会话中每个发送流的F_未决_字节之和;

o RX_DATA_PACKETS: a count of the number of received packets containing at least one User Data chunk since the last acknowledgement was sent, initially 0;

o RX_DATA_PACKETS:自上次确认发送以来,包含至少一个用户数据块的接收数据包数量的计数,最初为0;

o ACK_NOW: a boolean flag indicating whether an acknowledgement should be sent immediately, initially false;

o 立即确认:一个布尔标志,指示是否应立即发送确认,最初为false;

o DELACK_ALARM: an alarm to trigger an acknowledgement after a delay, initially unset;

o DELACK_报警:延迟后触发确认的报警,最初未设置;

o The state, at any time being one of the following values: the opening states S_IHELLO_SENT and S_KEYING_SENT, the open state S_OPEN, the closing states S_NEARCLOSE and S_FARCLOSE_LINGER, and the closed states S_CLOSED and S_OPEN_FAILED; and

o 状态,在任何时候为以下值之一:打开状态S_IHELLO_SENT和S_KEYING_SENT、打开状态S_open、关闭状态S_NEARCLOSE和S_FARCLOSE_LINGER,以及关闭状态S_closed和S_open_FAILED;和

o The role -- either Initiator or Responder -- of this end of the session.

o 会话结束时的角色(发起方或响应方)。

Note: The following diagram is only a summary of state transitions and their causing events, and is not a complete operational specification.

注意:下图只是状态转换及其导致事件的摘要,不是完整的操作规范。

          rcv IIKeying Glare
          far prevails +-------------+   ultimate open timeout
        +--------------|S_IHELLO_SENT|-------------+
        |              +-------------+             |
        |                     |rcv RHello          |
        |                     |                    v
        |                     v             +-------------+
        |<-----------(duplicate session?)   |S_OPEN_FAILED|
        |         yes         |no           +-------------+
        |                     |                    ^
        | rcv IIKeying Glare  v                    |
        | far prevails +-------------+             |
        |<-------------|S_KEYING_SENT|-------------+
        |              +-------------+   ultimate open timeout
        |                     |rcv RIKeying
        |                     |
        |       rcv           v
        |   +-+ IIKeying  +--------+ rcv Close Request
        |   |X|---------->| S_OPEN |--------------------+
        |   +-+           +--------+                    |
        |                   |    |ABRUPT CLOSE          |
        |      ORDERLY CLOSE|    |or rcv Close Ack      |
        |                   |    |or rcv IIKeying       |
        |                   |    |   session override   |
        |                   |    +-------+              |
        |                   v            |              v
        |             +-----------+      |     +-----------------+
        |             |S_NEARCLOSE|      |     |S_FARCLOSE_LINGER|
        |             +-----------+      |     +-----------------+
        |      rcv Close Ack|            |              |rcv Close Ack
        |      or 90 seconds|            v              |or 19 seconds
        |                   |       +--------+          |
        |                   +------>|S_CLOSED|<---------+
        +-------------------------->|        |
                                    +--------+
        
          rcv IIKeying Glare
          far prevails +-------------+   ultimate open timeout
        +--------------|S_IHELLO_SENT|-------------+
        |              +-------------+             |
        |                     |rcv RHello          |
        |                     |                    v
        |                     v             +-------------+
        |<-----------(duplicate session?)   |S_OPEN_FAILED|
        |         yes         |no           +-------------+
        |                     |                    ^
        | rcv IIKeying Glare  v                    |
        | far prevails +-------------+             |
        |<-------------|S_KEYING_SENT|-------------+
        |              +-------------+   ultimate open timeout
        |                     |rcv RIKeying
        |                     |
        |       rcv           v
        |   +-+ IIKeying  +--------+ rcv Close Request
        |   |X|---------->| S_OPEN |--------------------+
        |   +-+           +--------+                    |
        |                   |    |ABRUPT CLOSE          |
        |      ORDERLY CLOSE|    |or rcv Close Ack      |
        |                   |    |or rcv IIKeying       |
        |                   |    |   session override   |
        |                   |    +-------+              |
        |                   v            |              v
        |             +-----------+      |     +-----------------+
        |             |S_NEARCLOSE|      |     |S_FARCLOSE_LINGER|
        |             +-----------+      |     +-----------------+
        |      rcv Close Ack|            |              |rcv Close Ack
        |      or 90 seconds|            v              |or 19 seconds
        |                   |       +--------+          |
        |                   +------>|S_CLOSED|<---------+
        +-------------------------->|        |
                                    +--------+
        

Figure 8: Session State Diagram

图8:会话状态图

3.5.1. Startup
3.5.1. 启动
3.5.1.1. Normal Handshake
3.5.1.1. 正常握手

RTMFP sessions are established with a 4-way handshake in two round trips. The initiator begins by sending an IHello to one or more candidate addresses for the desired destination endpoint. A responder statelessly sends an RHello in response. The first correct RHello received at the initiator is selected; all others are ignored. The initiator computes its half of the session keying and sends an IIKeying. The responder receives the IIKeying and, if it is acceptable, computes its half of the session keying, at which point it can also compute the shared session keying and session nonces. The responder creates a new S_OPEN session with the initiator and sends an RIKeying. The initiator receives the RIKeying and, if it is acceptable, computes the shared session keying and session nonces. The initiator's session is now S_OPEN.

RTMFP会话通过两次往返的4路握手建立。启动器首先向所需目标端点的一个或多个候选地址发送IHello。响应者无状态地发送RHello作为响应。选择在启动器处接收到的第一个正确RHello;其他的都被忽略了。启动器计算其会话密钥的一半,并发送一个IIKeying。响应者接收IIKeying,如果可以接受,则计算其会话密钥的一半,此时还可以计算共享会话密钥和会话nonce。响应者与发起人创建一个新的S_OPEN会话,并发送一个RIKeying。发起者接收密钥,如果可以接受,则计算共享会话密钥和会话nonce。发起人的会话现在已打开。

        .     Initiator                                Responder     .
                      | IHello                         |
                      |(EPD,Tag)                       |
        S_IHELLO_SENT |(SID=0)                         |
                      |------------------------------->|
                      |                                |
                      |                         RHello |
                      |              (Tag,Cookie,RCert)|
                      |                         (SID=0)|
                      |<-------------------------------|
        S_KEYING_SENT |                                |
                      | IIKeying                       |
                      |(ISID,Cookie,ICert,SKIC,ISig)   |
                      |(SID=0)                         |
                      |------------------------------->|
                      |                                |
                      |                       RIKeying |
                      |                (RSID,SKRC,RSig)|
                      |          (SID=ISID,Key=Default)| S_OPEN
                      |<-------------------------------|
               S_OPEN |                                |
                      |          S E S S I O N         |
                      |<-------------------(SID=ISID)--|
                      |--(SID=RSID)------------------->|
        
        .     Initiator                                Responder     .
                      | IHello                         |
                      |(EPD,Tag)                       |
        S_IHELLO_SENT |(SID=0)                         |
                      |------------------------------->|
                      |                                |
                      |                         RHello |
                      |              (Tag,Cookie,RCert)|
                      |                         (SID=0)|
                      |<-------------------------------|
        S_KEYING_SENT |                                |
                      | IIKeying                       |
                      |(ISID,Cookie,ICert,SKIC,ISig)   |
                      |(SID=0)                         |
                      |------------------------------->|
                      |                                |
                      |                       RIKeying |
                      |                (RSID,SKRC,RSig)|
                      |          (SID=ISID,Key=Default)| S_OPEN
                      |<-------------------------------|
               S_OPEN |                                |
                      |          S E S S I O N         |
                      |<-------------------(SID=ISID)--|
                      |--(SID=RSID)------------------->|
        

Figure 9: Normal Handshake

图9:正常握手

In the following sections, the handshake is detailed from the perspectives of the initiator and responder.

在以下部分中,将从发起方和响应方的角度详细介绍握手。

3.5.1.1.1. Initiator
3.5.1.1.1. 发起者

The initiator determines that a session is needed for an Endpoint Discriminator. The initiator creates state for a new opening session and begins with a candidate endpoint address set containing at least one address. The new session is placed in the S_IHELLO_SENT state.

启动器确定端点鉴别器需要会话。发起程序为新的打开会话创建状态,并从至少包含一个地址的候选端点地址集开始。新会话处于S_IHELLO_发送状态。

If the session does not move to the S_OPEN state before an ultimate open timeout, the session has failed and moves to the S_OPEN_FAILED state. The RECOMMENDED ultimate open timeout is 95 seconds.

如果会话在最终打开超时之前未移动到S_打开状态,则会话已失败并移动到S_打开失败状态。建议的最终打开超时为95秒。

The initiator chooses a new, unique tag not used by any currently opening session. It is RECOMMENDED that the tag be cryptographically pseudorandom and be at least 8 bytes in length, so that it is hard to guess. The initiator constructs an IHello chunk (Section 2.3.2) with the Endpoint Discriminator and the tag.

发起者选择一个新的、唯一的标记,该标记未被任何当前打开的会话使用。建议标记采用密码伪随机,长度至少为8字节,因此很难猜测。启动器使用端点鉴别器和标记构造IHello块(第2.3.2节)。

While the initiator is in the S_IHELLO_SENT state, it sends the IHello to each candidate endpoint address in the set, on a backoff schedule. The backoff SHOULD NOT be less than multiplicative, with not less than 1.5 seconds added to the interval between each attempt. The backoff SHOULD be scheduled separately for each candidate address, since new candidates can be added over time.

当启动器处于S_IHELLO_SENT状态时,它会按照退避计划将IHELLO发送到集合中的每个候选端点地址。退避不应小于乘法,每次尝试之间的间隔增加不少于1.5秒。应为每个候选人地址单独安排退避,因为随着时间的推移,可能会添加新的候选人。

If the initiator receives a Redirect chunk (Section 2.3.5) with a tag echo matching this session, AND this session is in the S_IHELLO_SENT state, then for each redirect destination indicated in the Redirect: if the candidate endpoint address set contains fewer than REDIRECT_THRESHOLD addresses, add the indicated redirect destination to the candidate endpoint address set. REDIRECT_THRESHOLD SHOULD NOT be more than 24.

如果启动器接收到一个重定向区块(第2.3.5节),该区块带有与该会话匹配的标记回显,且该会话处于S_IHELLO_发送状态,则对于重定向中指示的每个重定向目标:如果候选端点地址集包含的地址少于重定向阈值地址,将指示的重定向目标添加到候选端点地址集。重定向\u阈值不应超过24。

If the initiator receives an RHello chunk (Section 2.3.4) with a tag echo matching this session, AND this session is in the S_IHELLO_SENT state, AND the responder certificate matches the desired Endpoint Discriminator, AND the certificate is authentic according to the Cryptography Profile, then:

如果启动器接收到一个RHello块(第2.3.4节),该块具有与此会话匹配的标记回显,并且此会话处于S_IHELLO_发送状态,并且响应者证书与所需的端点鉴别器匹配,并且根据加密配置文件,证书是可信的,则:

1. If the Canonical Endpoint Discriminator for the responder certificate matches the Canonical Endpoint Discriminator of another existing session in the S_KEYING_SENT or S_OPEN states, AND the certificate of the other opening session matches the desired Endpoint Discriminator, then this session is a duplicate and SHOULD be aborted in favor of the other existing session; otherwise,

1. 如果响应者证书的规范端点鉴别器与S_KEYING_SENT或S_OPEN状态下另一个现有会话的规范端点鉴别器匹配,并且另一个打开会话的证书与所需的端点鉴别器匹配,那么这个会话是重复的,应该中止,以支持其他现有会话;否则

2. Move to the S_KEYING_SENT state. Set DESTADDR, the far-end address for the session, to the address from which this RHello was received. The initiator chooses a new, unique receive session ID, not used by any other session, for the responder to use when sending packets to the initiator. It computes a Session Key Initiator Component appropriate to the responder's certificate according to the Cryptography Profile. Using this data and the cookie from the RHello, the initiator constructs and signs an IIKeying chunk (Section 2.3.7).

2. 移动到S_键控_发送状态。将会话的远端地址DESTADDR设置为接收此RHello的地址。发起方选择一个新的、唯一的接收会话ID,该ID不被任何其他会话使用,以便响应方在向发起方发送数据包时使用。它根据加密配置文件计算适合于响应者证书的会话密钥启动器组件。使用此数据和RHello中的cookie,发起人构造并签署一个IIKeying块(第2.3.7节)。

While the initiator is in the S_KEYING_SENT state, it sends the IIKeying to DESTADDR on a backoff schedule. The backoff SHOULD NOT be less than multiplicative, with not less than 1.5 seconds added to the interval between each attempt.

当启动器处于S_KEYING_SENT状态时,它会按照退避计划将IIKeying发送到DESTADDR。退避不应小于乘法,每次尝试之间的间隔增加不少于1.5秒。

If the initiator receives an RIKeying chunk (Section 2.3.8) in a packet with this session's receive session identifier, AND this session is in the S_KEYING_SENT state, AND the signature in the chunk is authentic according to the far end's certificate (from the RHello), AND the Session Key Responder Component successfully combines with the Session Key Initiator Component and the near and far certificates to form the shared session keys and nonces according to the Cryptography Profile, then the session has opened successfully. The session moves to the S_OPEN state. The send session identifier is set from the RIKeying. Packet encryption, decryption, and verification now use the newly computed shared session keys, and the session nonces are available for application-layer cryptographic challenges.

如果发起方接收到一个数据包中的密钥块(第2.3.8节),该数据包具有该会话的接收会话标识符,并且该会话处于s_-KEYING_-SENT状态,并且根据远端的证书(来自RHello),该数据块中的签名是可信的,会话密钥响应器组件根据密码配置文件成功地与会话密钥发起器组件和远近证书组合,形成共享会话密钥和nonce,会话成功打开。会话将移动到S_打开状态。发送会话标识符是通过RIKeying设置的。数据包加密、解密和验证现在使用新计算的共享会话密钥,会话nonce可用于应用层加密挑战。

3.5.1.1.2. Responder
3.5.1.1.2. 应答器

On receipt of an IHello chunk (Section 2.3.2) with an Endpoint Discriminator that selects its identity, an endpoint SHOULD construct an RHello chunk (Section 2.3.4) and send it to the address from which the IHello was received. To avoid a potential resource exhaustion denial of service, the endpoint SHOULD NOT create any persistent state associated with the IHello. The endpoint MUST generate the cookie for the RHello in such a way that it can be recognized as authentic and valid when echoed in an IIKeying. The endpoint SHOULD use the address from which the IHello was received as part of the cookie generation formula. Cookies SHOULD be valid only for a limited time; that lifetime SHOULD NOT be less than 95 seconds (the recommended ultimate session open timeout).

在接收到带有端点鉴别器的IHello区块(第2.3.2节)并选择其标识时,端点应构造一个RHello区块(第2.3.4节),并将其发送到接收IHello的地址。为了避免潜在的资源耗尽拒绝服务,端点不应创建与IHello关联的任何持久状态。端点必须为RHello生成cookie,以便在IIKeying中回显时可以将其识别为真实有效的cookie。端点应使用接收IHello的地址作为cookie生成公式的一部分。Cookie只能在有限的时间内有效;该生存期不应少于95秒(建议的最终会话打开超时)。

On receipt of an FIHello chunk (Section 2.3.3) from a Forwarder (Section 3.5.1.5) where the Endpoint Discriminator selects its identity, an endpoint SHOULD do one of the following:

从转发器(第3.5.1.5节)接收到FIHello区块(第2.3.3节),其中端点鉴别器选择其标识,端点应执行以下操作之一:

1. Compute, construct, and send an RHello as though the FIHello was an IHello received from the indicated reply address; or

1. 计算、构造并发送RHello,就像FIHello是从指定的回复地址接收的IHello一样;或

2. Construct and send an Implied Redirect (Section 2.3.5) to the FIHello's reply address; or

2. 构造并向FIHello的回复地址发送隐含重定向(第2.3.5节);或

3. Ignore this FIHello.

3. 别理这个,你好。

On receipt of an IIKeying chunk (Section 2.3.7), if the cookie is not authentic or if it has expired, ignore this IIKeying; otherwise,

在收到IIKeying区块(第2.3.7节)时,如果cookie不真实或已过期,则忽略此IIKeying;否则

On receipt of an IIKeying chunk, if the cookie appears authentic but does not match the address from which the IIKeying's packet was received, perform the special processing at Cookie Change (Section 3.5.1.2); otherwise,

收到IIKeying数据块后,如果cookie看起来是真实的,但与接收IIKeying数据包的地址不匹配,则在cookie更改时执行特殊处理(第3.5.1.2节);否则

On receipt of an IIKeying with an authentic and valid cookie, if the certificate is authentic according to the Cryptography Profile, AND the signature in the chunk is authentic according to the far end's certificate and the Cryptography Profile, AND the Session Key Initiator Component is acceptable, then:

在收到带有真实有效cookie的IIKeying时,如果根据加密配置文件,证书是真实的,并且根据远端的证书和加密配置文件,区块中的签名是真实的,并且会话密钥启动器组件是可接受的,则:

1. If the address from which this IIKeying was received corresponds to an opening session in the S_IHELLO_SENT or S_KEYING_SENT state, perform the special processing at Glare (Section 3.5.1.3); otherwise,

1. 如果接收该IIKeying的地址对应于S_IHELLO_发送或S_KEYING_发送状态下的打开会话,则在眩光下执行特殊处理(第3.5.1.3节);否则

2. If the address from which this IIKeying was received corresponds to a session in the S_OPEN state, then:

2. 如果接收此IIKeying的地址对应于处于S_打开状态的会话,则:

1. If the receiver was the Responder for the S_OPEN session and the session identifier, certificate, and Session Key Initiator Component are identical to those of the S_OPEN session, this IIKeying is a retransmission, so resend the S_OPEN session's RIKeying using the Default Session Key as specified below; otherwise,

1. 如果接收器是S_开放会话的响应者,并且会话标识符、证书和会话密钥发起程序组件与S_开放会话的相同,则此IIKeying是重传,因此使用以下指定的默认会话密钥重新发送S_开放会话的RIKeying;否则

2. If the certificate from this IIKeying does not override the certificate of the S_OPEN session, ignore this IIKeying; otherwise,

2. 如果此IIKeying的证书未覆盖S_OPEN会话的证书,则忽略此IIKeying;否则

3. The certificate from this IIKeying overrides the certificate of the S_OPEN session; this is a new opening session from the same identity, and the existing S_OPEN session is stale. Move the existing S_OPEN session to S_CLOSED and abort all of its flows (signaling exceptions to the user), then continue processing this IIKeying.

3. 来自此IIKeying的证书覆盖S_开放会话的证书;这是来自同一标识的新打开会话,而现有的S_打开会话已过时。将现有的S_OPEN会话移动到S_CLOSED并中止其所有流(向用户发送异常信号),然后继续处理此IIKeying。

Otherwise,

否则

3. Compute a Session Key Responder Component and choose a new, unique receive session ID not used by any other session for the initiator to use when sending packets to the responder. Using this data, construct and, with the Session Key Initiator Component, sign an RIKeying chunk (Section 2.3.8). Using the Session Key Initiator and Responder Components and the near and far certificates, the responder combines and computes the shared session keys and nonces according to the Cryptography Profile. The responder creates a new session in the S_OPEN state, with the far-endpoint address DESTADDR taken from the source address of the packet containing the IIKeying and the send session identifier taken from the IIKeying. The responder sends the RIKeying to the initiator using the Default Session Key and the requested send session identifier. Packet encryption, decryption, and verification of all future packets for this session use the newly computed keys, and the session nonces are available for application-layer cryptographic challenges.

3. 计算会话密钥响应程序组件,并选择一个新的、唯一的接收会话ID,该ID未被任何其他会话使用,以便启动器在向响应程序发送数据包时使用。使用此数据,构造并使用会话密钥启动器组件对密钥块进行签名(第2.3.8节)。使用会话密钥启动器和响应程序组件以及近端和远端证书,响应程序根据加密配置文件组合并计算共享会话密钥和nonce。响应程序在S_OPEN状态下创建一个新会话,远端端点地址DESTADDR取自包含IIKeying的数据包的源地址,发送会话标识符取自IIKeying。响应程序使用默认会话密钥和请求的发送会话标识符将密钥发送给启动器。此会话的所有未来数据包的数据包加密、解密和验证使用新计算的密钥,并且会话nonce可用于应用层加密挑战。

3.5.1.2. Cookie Change
3.5.1.2. 零钱

In some circumstances, the responder may generate an RHello cookie for an initiator's address that isn't the address the initiator would use when sending packets directly to the responder. This can happen, for example, when the initiator has multiple local addresses and uses one address to reach a Forwarder (Section 3.5.1.5) but another to reach the responder.

在某些情况下,响应者可能会为发起者的地址生成RHello cookie,该地址不是发起者直接向响应者发送数据包时使用的地址。例如,当启动器具有多个本地地址,并使用一个地址到达转发器(第3.5.1.5节),但使用另一个地址到达响应者时,可能会发生这种情况。

Consider the following example:

考虑下面的例子:

   Initiator                    Forwarder                     Responder
   | IHello                         |                                 |
   |(Src=Ix)                        |                                 |
   |------------------------------->|                                 |
   |                                | FIHello                         |
   |                                |(RA=Ix)                          |
   |                                |-------------------------------->|
   |                                                                  |
   |                                                           RHello |
   |                                                       (Cookie:Ix)|
   |<-----------------------------------------------------------------|
   |                                                                  |
   | IIKeying                                                         |
   |(Cookie:Ix,Src=Iy)                                                |
   |----------------------------------------------------------------->|
   |                                                                  |
   |                                             RHello Cookie Change |
   |                                             (Cookie:Ix,Cookie:Iy)|
   |<-----------------------------------------------------------------|
   |                                                                  |
   | IIKeying                                                         |
   |(Cookie:Iy)                                                       |
   |----------------------------------------------------------------->|
   |                                                                  |
   |                                                         RIKeying |
   |<-----------------------------------------------------------------|
   |                                                                  |
   |<======================== S E S S I O N =========================>|
        
   Initiator                    Forwarder                     Responder
   | IHello                         |                                 |
   |(Src=Ix)                        |                                 |
   |------------------------------->|                                 |
   |                                | FIHello                         |
   |                                |(RA=Ix)                          |
   |                                |-------------------------------->|
   |                                                                  |
   |                                                           RHello |
   |                                                       (Cookie:Ix)|
   |<-----------------------------------------------------------------|
   |                                                                  |
   | IIKeying                                                         |
   |(Cookie:Ix,Src=Iy)                                                |
   |----------------------------------------------------------------->|
   |                                                                  |
   |                                             RHello Cookie Change |
   |                                             (Cookie:Ix,Cookie:Iy)|
   |<-----------------------------------------------------------------|
   |                                                                  |
   | IIKeying                                                         |
   |(Cookie:Iy)                                                       |
   |----------------------------------------------------------------->|
   |                                                                  |
   |                                                         RIKeying |
   |<-----------------------------------------------------------------|
   |                                                                  |
   |<======================== S E S S I O N =========================>|
        

Figure 10: Handshake with Cookie Change

图10:使用Cookie更改进行握手

The initiator has two network interfaces: a first preferred interface with address Ix = 192.0.2.100:50000, and a second with address Iy = 198.51.100.101:50001. The responder has one interface with address Ry = 198.51.100.200:51000, on the same network as the initiator's second interface. The initiator uses its first interface to reach a Forwarder. The Forwarder observes the initiator's address of Ix and sends a Forwarded IHello (Section 2.3.3) to the responder. The responder treats this as if it were an IHello from Ix, calculates a corresponding cookie, and sends an RHello to Ix. The initiator receives this RHello from Ry and selects that address as the destination for the session. It then sends an IIKeying, copying the cookie from the RHello. However, since the source of the RHello is Ry, on a network to which the initiator is directly connected, the initiator uses its second interface Iy to send the IIKeying. The responder, on receiving the IIKeying, will compare the cookie to the

启动器有两个网络接口:第一个首选接口的地址为Ix=192.0.2.100:50000,第二个首选接口的地址为Iy=198.51.100.101:50001。响应者有一个地址为Ry=198.51.100.200:51000的接口,与启动器的第二个接口位于同一网络上。启动器使用其第一个接口与转发器联系。转发方观察发起方的Ix地址,并向响应方发送转发的IHello(第2.3.3节)。响应者将其视为来自Ix的IHello,计算相应的cookie,并向Ix发送RHello。启动器从Ry接收此RHello,并选择该地址作为会话的目标。然后它发送一个键盘输入,从RHello复制cookie。但是,由于RHello的源是Ry,在启动器直接连接的网络上,启动器使用其第二个接口Iy发送IIKeying。响应者在接收到IIKeying时,会将cookie与

expected value based on the source address of the packet, and since the IIKeying source doesn't match the IHello source used to generate the cookie, the responder will reject the IIKeying.

基于数据包的源地址的预期值,并且由于IIKeying源与用于生成cookie的IHello源不匹配,响应程序将拒绝IIKeying。

If the responder determines that it generated the cookie in the IIKeying but the cookie doesn't match the sender's address (for example, if the cookie is in two parts, with a first part generated independently of the initiator's address and a second part dependent on the address), the responder SHOULD generate a new cookie based on the address from which the IIKeying was received and send an RHello Cookie Change chunk (Section 2.3.6) to the source of the IIKeying, using the session ID from the IIKeying and the Default Session Key.

如果响应者确定它在IIKeying中生成了cookie,但cookie与发送者的地址不匹配(例如,如果cookie分为两部分,第一部分独立于发起人的地址生成,第二部分依赖于地址),响应者应根据接收IIKeying的地址生成新cookie,并使用IIKeying中的会话ID和默认会话密钥,将RHello cookie更改块(第2.3.6节)发送到IIKeying的源。

If the initiator receives an RHello Cookie Change chunk for a session in the S_KEYING_SENT state, AND the old cookie matches the one originally sent to the responder, then the initiator adopts the new cookie, constructs and signs a new IIKeying chunk, and sends the new IIKeying to the responder. The initiator SHOULD NOT change the cookie for a session more than once.

如果发起者在S_KEYING_SENT状态下收到会话的RHello Cookie更改块,并且旧Cookie与最初发送给响应者的Cookie匹配,则发起者采用新Cookie,构造并签署新的IIKeying块,并将新的IIKeying发送给响应者。启动器不应多次更改会话的cookie。

3.5.1.3. Glare
3.5.1.3. 怒目而视

Glare occurs when two endpoints attempt to initiate sessions to each other concurrently. Glare is detected by receipt of a valid and authentic IIKeying from an endpoint address that is a destination for an opening session. Only one session is allowed between a pair of endpoints.

当两个端点试图同时启动彼此的会话时,会发生眩光。眩光是通过从作为开放会话目的地的端点地址接收有效且真实的IIKeying来检测的。一对端点之间只允许一个会话。

Glare is resolved by comparing the certificate in the received IIKeying with the near end's certificate. The Cryptography Profile defines a certificate comparison function to determine the prevailing endpoint when there is glare.

通过将接收到的IIKeying中的证书与近端的证书进行比较来解决眩光问题。加密配置文件定义了一个证书比较函数,用于在出现眩光时确定主要端点。

If the near end prevails, discard and ignore the received IIKeying. The far end will abort its opening session on receipt of IIKeying from the near end.

如果近端占优势,则丢弃并忽略接收到的IIKeying。远端将在收到来自近端的IIKeying后中止其开始会话。

Otherwise, the far end prevails:

否则,以远端为准:

1. If the certificate in the IIKeying overrides the certificate associated with the near opening session according to the Cryptography Profile, then abort and destroy the near opening session. Then,

1. 如果IIKeying中的证书根据加密配置文件覆盖与即将打开的会话相关联的证书,则中止并销毁即将打开的会话。然后

2. Continue with normal Responder IIKeying processing (Section 3.5.1.1.2).

2. 继续进行正常应答器IIKeying处理(第3.5.1.1.2节)。

3.5.1.4. Redirector
3.5.1.4. 重定向器
        +-----------+           +------------+          +-----------+
        | Initiator |---------->| Redirector |          | Responder |
        |           |<----------|            |          |           |
        |           |           +------------+          |           |
        |           |<=================================>|           |
        +-----------+                                   +-----------+
        
        +-----------+           +------------+          +-----------+
        | Initiator |---------->| Redirector |          | Responder |
        |           |<----------|            |          |           |
        |           |           +------------+          |           |
        |           |<=================================>|           |
        +-----------+                                   +-----------+
        

Figure 11: Redirector

图11:重定向器

A Redirector acts like a name server for Endpoint Discriminators. An initiator MAY use a Redirector to discover additional candidate endpoint addresses for a desired endpoint.

重定向器的作用类似于端点鉴别器的名称服务器。发起者可以使用重定向器来发现所需端点的其他候选端点地址。

On receipt of an IHello chunk with an Endpoint Discriminator that does not select the Redirector's identity, the Redirector constructs and sends back to the initiator a Responder Redirect chunk (Section 2.3.5) containing one or more additional candidate addresses for the indicated endpoint.

在接收到带有端点鉴别器的IHello区块(该端点鉴别器未选择重定向器的标识)时,重定向器构造并向启动器发回一个响应器重定向区块(第2.3.5节),该区块包含指示端点的一个或多个额外候选地址。

   Initiator                   Redirector                     Responder
   | IHello                         |                                 |
   |------------------------------->|                                 |
   |                                |                                 |
   |                       Redirect |                                 |
   |<-------------------------------|                                 |
   |                                                                  |
   | IHello                                                           |
   |----------------------------------------------------------------->|
   |                                                                  |
   |                                                           RHello |
   |<-----------------------------------------------------------------|
   |                                                                  |
   | IIKeying                                                         |
   |----------------------------------------------------------------->|
   |                                                                  |
   |                                                         RIKeying |
   |<-----------------------------------------------------------------|
   |                                                                  |
   |<======================== S E S S I O N =========================>|
        
   Initiator                   Redirector                     Responder
   | IHello                         |                                 |
   |------------------------------->|                                 |
   |                                |                                 |
   |                       Redirect |                                 |
   |<-------------------------------|                                 |
   |                                                                  |
   | IHello                                                           |
   |----------------------------------------------------------------->|
   |                                                                  |
   |                                                           RHello |
   |<-----------------------------------------------------------------|
   |                                                                  |
   | IIKeying                                                         |
   |----------------------------------------------------------------->|
   |                                                                  |
   |                                                         RIKeying |
   |<-----------------------------------------------------------------|
   |                                                                  |
   |<======================== S E S S I O N =========================>|
        

Figure 12: Handshake Using a Redirector

图12:使用重定向器的握手

Deployment Design Note: Redirectors SHOULD NOT initiate new sessions to endpoints that might use the Redirector's address as a candidate for another endpoint, since the far end might interpret the Redirector's IIKeying as glare for the far end's initiation to the other endpoint.

部署设计说明:重定向器不应向可能使用重定向器地址作为另一个端点候选地址的端点发起新会话,因为远端可能会将重定向器的iKeying解释为远端向另一个端点发起的眩光。

3.5.1.5. Forwarder
3.5.1.5. 促进者
         +-----------+     +-----------+     +---+     +-----------+
         | Initiator |---->| Forwarder |<===>| N |<===>| Responder |
         |           |     +-----------+     | A |     |           |
         |           |<=====================>| T |<===>|           |
         +-----------+                       +---+     +-----------+
        
         +-----------+     +-----------+     +---+     +-----------+
         | Initiator |---->| Forwarder |<===>| N |<===>| Responder |
         |           |     +-----------+     | A |     |           |
         |           |<=====================>| T |<===>|           |
         +-----------+                       +---+     +-----------+
        

Figure 13: Forwarder

图13:货运代理

A responder might be behind a NAT or firewall that doesn't allow inbound packets to reach the endpoint until it first sends an outbound packet for a particular far-endpoint address.

响应程序可能位于NAT或防火墙之后,该NAT或防火墙不允许入站数据包到达端点,直到它首先为特定的远端端点地址发送出站数据包。

A Forwarder's endpoint address MAY be a candidate address for another endpoint. A responder MAY use a Forwarder to receive FIHello chunks sent on behalf of an initiator.

转发器的端点地址可以是另一个端点的候选地址。响应者可以使用转发器来接收代表发起者发送的FIHello块。

On receipt of an IHello chunk with an Endpoint Discriminator that does not select the Forwarder's identity, if the Forwarder has an S_OPEN session with an endpoint whose certificate matches the desired Endpoint Discriminator, the Forwarder constructs and sends an FIHello chunk (Section 2.3.3) to the selected endpoint over the S_OPEN session, using the tag and Endpoint Discriminator from the IHello chunk and the source address of the packet containing the IHello for the corresponding fields of the FIHello.

接收到带有端点鉴别器的IHello区块时,如果转发器与证书与所需端点鉴别器匹配的端点有一个s_开放会话,则转发器构建并通过s_开放会话向所选端点发送FIHello区块(第2.3.3节),使用IHello区块中的标记和端点鉴别器,以及包含IHello的数据包的源地址,用于FIHello的相应字段。

On receipt of an FIHello chunk, a responder might send an RHello or Implied Redirect to the original source of the IHello (Section 3.5.1.1.2), potentially allowing future packets to flow directly between the initiator and responder through the NAT or firewall.

收到FIHello区块后,响应者可能会向IHello的原始源发送RHello或隐含重定向(第3.5.1.1.2节),这可能允许将来的数据包通过NAT或防火墙直接在启动器和响应者之间流动。

   Initiator                    Forwarder           NAT       Responder
   | IHello                         |                |                |
   |------------------------------->|                |                |
   |                                | FIHello        |                |
   |                                |--------------->|--------------->|
   |                                                 |                |
   |                                                 |         RHello |
   |                                                 :<---------------|
   |<------------------------------------------------:                |
   |                                                 :                |
   | IIKeying                                        :                |
   |-------------------------------------------------:--------------->|
   |                                                 :                |
   |                                                 :       RIKeying |
   |                                                 :<---------------|
   |<------------------------------------------------:                |
   |                                                 :                |
   |<======================== S E S S I O N ========>:<==============>|
        
   Initiator                    Forwarder           NAT       Responder
   | IHello                         |                |                |
   |------------------------------->|                |                |
   |                                | FIHello        |                |
   |                                |--------------->|--------------->|
   |                                                 |                |
   |                                                 |         RHello |
   |                                                 :<---------------|
   |<------------------------------------------------:                |
   |                                                 :                |
   | IIKeying                                        :                |
   |-------------------------------------------------:--------------->|
   |                                                 :                |
   |                                                 :       RIKeying |
   |                                                 :<---------------|
   |<------------------------------------------------:                |
   |                                                 :                |
   |<======================== S E S S I O N ========>:<==============>|
        

Figure 14: Forwarder Handshake where Responder Sends an RHello

图14:应答器发送RHello的转发器握手

   Initiator                    Forwarder           NAT       Responder
   | IHello                         |                |                |
   |------------------------------->|                |                |
   |                                | FIHello        |                |
   |                                |--------------->|--------------->|
   |                                                 |                |
   |                                                 |       Redirect |
   |                                                 | (Implied,RD={})|
   |                                                 :<---------------|
   |<------------------------------------------------:                |
   |                                                 :                |
   | IHello                                          :                |
   |------------------------------------------------>:--------------->|
   |                                                 :                |
   |                                                 :         RHello |
   |                                                 :<---------------|
   |<------------------------------------------------:                |
   |                                                 :                |
   | IIKeying                                        :                |
   |------------------------------------------------>:--------------->|
   |                                                 :                |
   |                                                 :       RIKeying |
   |                                                 :<---------------|
   |<------------------------------------------------:                |
   |                                                 :                |
   |<======================== S E S S I O N ========>:<==============>|
        
   Initiator                    Forwarder           NAT       Responder
   | IHello                         |                |                |
   |------------------------------->|                |                |
   |                                | FIHello        |                |
   |                                |--------------->|--------------->|
   |                                                 |                |
   |                                                 |       Redirect |
   |                                                 | (Implied,RD={})|
   |                                                 :<---------------|
   |<------------------------------------------------:                |
   |                                                 :                |
   | IHello                                          :                |
   |------------------------------------------------>:--------------->|
   |                                                 :                |
   |                                                 :         RHello |
   |                                                 :<---------------|
   |<------------------------------------------------:                |
   |                                                 :                |
   | IIKeying                                        :                |
   |------------------------------------------------>:--------------->|
   |                                                 :                |
   |                                                 :       RIKeying |
   |                                                 :<---------------|
   |<------------------------------------------------:                |
   |                                                 :                |
   |<======================== S E S S I O N ========>:<==============>|
        

Figure 15: Forwarder Handshake where Responder Sends an Implied Redirect

图15:应答器发送隐含重定向的转发器握手

3.5.1.6. Redirector and Forwarder with NAT
3.5.1.6. 具有NAT的重定向器和转发器
             +---+       +---+       +---+      +---+      +---+
             | I |       | N |       | I |      | N |      | R |
             | n |------>| A |------>| n |      | A |      | e |
             | i |       | T |       | t |<====>| T |<====>| s |
             | t |<------|   |<------| r |      |   |      | p |
             | i |       |   |       | o |      |   |      | o |
             | a |       |   |       +---+      |   |      | n |
             | t |       |   |                  |   |      | d |
             | o |<=====>|   |<================>|   |<====>| e |
             | r |       |   |                  |   |      | r |
             +---+       +---+                  +---+      +---+
        
             +---+       +---+       +---+      +---+      +---+
             | I |       | N |       | I |      | N |      | R |
             | n |------>| A |------>| n |      | A |      | e |
             | i |       | T |       | t |<====>| T |<====>| s |
             | t |<------|   |<------| r |      |   |      | p |
             | i |       |   |       | o |      |   |      | o |
             | a |       |   |       +---+      |   |      | n |
             | t |       |   |                  |   |      | d |
             | o |<=====>|   |<================>|   |<====>| e |
             | r |       |   |                  |   |      | r |
             +---+       +---+                  +---+      +---+
        

Figure 16: Introduction Service for Initiator and Responder behind NATs

图16:NAT后面的启动器和响应程序的介绍服务

An initiator and responder might each be behind distinct NATs or firewalls that don't allow inbound packets to reach the respective endpoints until each first sends an outbound packet for a particular far-endpoint address.

发起方和响应方可能各自位于不同的NAT或防火墙后面,这些NAT或防火墙不允许入站数据包到达各自的端点,直到各自首先为特定的远端端点地址发送出站数据包。

An introduction service comprising Redirector and Forwarder functions may facilitate direct communication between endpoints each behind a NAT.

包括重定向器和转发器功能的引入服务可促进NAT后面的每个端点之间的直接通信。

The responder is registered with the introduction service via an S_OPEN session to it. The service observes and records the responder's public NAT address as the DESTADDR of the S_OPEN session. The service MAY record other addresses for the responder, for example addresses that the responder self-reports as being directly attached.

响应者通过S_开放会话向介绍服务注册。服务观察并记录响应者的公共NAT地址,作为SU开放会话的DESTADDR。服务可以记录响应者的其他地址,例如响应者自我报告为直接连接的地址。

The initiator begins with an address of the introduction service as an initial candidate. The Redirector portion of the service sends to the initiator a Responder Redirect containing at least the responder's public NAT address as previously recorded. The Forwarder portion of the service sends to the responder a Forwarded IHello containing the initiator's public NAT address as observed to be the source of the IHello.

启动器以介绍服务的地址作为初始候选地址开始。服务的重定向器部分向启动器发送至少包含先前记录的响应器公共NAT地址的响应器重定向。服务的转发器部分向响应者发送转发的IHello,其中包含观察到的作为IHello源的启动器的公共NAT地址。

The responder sends an RHello to the initiator's public NAT address in response to the FIHello. This will allow inbound packets to the responder through its NAT from the initiator's public NAT address.

响应者向发起者的公共NAT地址发送RHello以响应FIHello。这将允许入站数据包通过其NAT从发起方的公共NAT地址发送到响应方。

The initiator sends an IHello to the responder's public NAT address in response to the Responder Redirect. This will allow inbound packets to the initiator through its NAT from the responder's public NAT address.

发起方向响应方的公共NAT地址发送IHello以响应响应方重定向。这将允许入站数据包通过其NAT从响应方的公共NAT地址发送到发起方。

With transit paths created in both NATs, normal session startup can proceed.

通过在两个NAT中创建传输路径,可以继续正常会话启动。

   Initiator     NAT-I    Redirector+Forwarder     NAT-R      Responder
   |               |                |                |                |
   | IHello        |                |                |                |
   |(Dst=Intro)    |                |                |                |
   |-------------->|                |                |                |
   |               |--------------->|                |                |
   |               |                | FIHello        |                |
   |               |                |(RA=NAT-I-Pub)  |                |
   |               |                |--------------->|--------------->|
   |               |       Redirect |                |                |
   |               | (RD={NAT-R-Pub,|                |                |
   |               |           ...})|                |                |
   |<--------------|<---------------|                |                |
   |               |                                 |         RHello |
   |               |                                 | (Dst=NAT-I-Pub)|
   |               |                                 :<---------------|
   |               | (*)  <--------------------------:                |
   | IHello        |                                 :                |
   |(Dst=NAT-R-Pub)|                                 :                |
   |-------------->:                                 :                |
   |               :-------------------------------->:--------------->|
   |               :                                 :                |
   |               :                                 :         RHello |
   |               :                                 :<---------------|
   |<--------------:<--------------------------------:                |
   |               :                                 :                |
   | IIKeying      :                                 :                |
   |-------------->:                                 :                |
   |               :-------------------------------->:--------------->|
   |               :                                 :                |
   |               :                                 :       RIKeying |
   |               :                                 :<---------------|
   |<--------------:<--------------------------------:                |
   |               :                                 :                |
   |<=============>:<======== S E S S I O N ========>:<==============>|
        
   Initiator     NAT-I    Redirector+Forwarder     NAT-R      Responder
   |               |                |                |                |
   | IHello        |                |                |                |
   |(Dst=Intro)    |                |                |                |
   |-------------->|                |                |                |
   |               |--------------->|                |                |
   |               |                | FIHello        |                |
   |               |                |(RA=NAT-I-Pub)  |                |
   |               |                |--------------->|--------------->|
   |               |       Redirect |                |                |
   |               | (RD={NAT-R-Pub,|                |                |
   |               |           ...})|                |                |
   |<--------------|<---------------|                |                |
   |               |                                 |         RHello |
   |               |                                 | (Dst=NAT-I-Pub)|
   |               |                                 :<---------------|
   |               | (*)  <--------------------------:                |
   | IHello        |                                 :                |
   |(Dst=NAT-R-Pub)|                                 :                |
   |-------------->:                                 :                |
   |               :-------------------------------->:--------------->|
   |               :                                 :                |
   |               :                                 :         RHello |
   |               :                                 :<---------------|
   |<--------------:<--------------------------------:                |
   |               :                                 :                |
   | IIKeying      :                                 :                |
   |-------------->:                                 :                |
   |               :-------------------------------->:--------------->|
   |               :                                 :                |
   |               :                                 :       RIKeying |
   |               :                                 :<---------------|
   |<--------------:<--------------------------------:                |
   |               :                                 :                |
   |<=============>:<======== S E S S I O N ========>:<==============>|
        

Figure 17: Handshake with Redirector and Forwarder

图17:与重定向器和转发器的握手

At the point in Figure 17 marked (*), the responder's RHello from the FIHello might arrive at the initiator's NAT before or after the initiator's IHello is sent outbound to the responder's public NAT address. If it arrives before, it may be dropped by the NAT. If it arrives after, it will transit the NAT and trigger keying without waiting for another round-trip time. The timing of this race depends, among other factors, on the relative distances of the initiator and responder from each other and from the introduction service.

在图17中标记(*)的点处,来自FIHello的响应者的RHello可能在启动器的IHello被发送到响应者的公共NAT地址之前或之后到达启动器的NAT。如果它提前到达,可能会被NAT丢弃。如果它在之后到达,它将传输NAT并触发键控,而无需等待另一个往返时间。除其他因素外,此竞赛的计时取决于发起方和响应方彼此之间以及与引入服务之间的相对距离。

3.5.1.7. Load Distribution and Fault Tolerance
3.5.1.7. 负载分配与容错
             +---+    IHello/RHello    +-------------+
             | I |<------------------->| Responder 1 |
             | n |                     +-------------+
             | i |  SESSION  +-------------+
             | t |<=========>| Responder 2 |
             | i |           +-------------+
             | a |   IHello...                 +----------------+
             | t |-------------------------> X | Dead Responder |
             | o |                             +----------------+
             | r |  IHello/RHello   +-------------+
             |   |<---------------->| Responder N |
             +---+                  +-------------+
        
             +---+    IHello/RHello    +-------------+
             | I |<------------------->| Responder 1 |
             | n |                     +-------------+
             | i |  SESSION  +-------------+
             | t |<=========>| Responder 2 |
             | i |           +-------------+
             | a |   IHello...                 +----------------+
             | t |-------------------------> X | Dead Responder |
             | o |                             +----------------+
             | r |  IHello/RHello   +-------------+
             |   |<---------------->| Responder N |
             +---+                  +-------------+
        

Figure 18: Parallel Open to Multiple Endpoints

图18:并行开放到多个端点

As specified in Section 3.2, more than one endpoint is allowed to be selected by one Endpoint Discriminator. This will typically be the case for a set of servers, any of which could accommodate a connecting client.

如第3.2节所述,允许一个端点鉴别器选择多个端点。这通常是一组服务器的情况,其中任何一个都可以容纳一个连接的客户端。

As specified in Section 3.5.1.1.1, an initiator is allowed to use multiple candidate endpoint addresses when starting a session, and the sender of the first acceptable RHello chunk to be received is selected to complete the session, with later responses ignored. An initiator can start with the multiple candidate endpoint addresses, or it may learn them during startup from one or more Redirectors (Section 3.5.1.4).

如第3.5.1.1.1节所述,在启动会话时,允许启动器使用多个候选端点地址,并选择要接收的第一个可接受RHello块的发送方来完成会话,随后的响应将被忽略。启动器可以从多个候选端点地址开始,也可以在启动过程中从一个或多个重定向器中学习这些地址(第3.5.1.4节)。

Parallel open to multiple endpoints for the same Endpoint Discriminator, combined with selection by earliest RHello, can be used for load distribution and fault tolerance. The cost at each endpoint that is not selected is limited to receiving and processing an IHello, and generating and sending an RHello.

同一端点鉴别器的多个端点并行开放,结合早期RHello的选择,可用于负载分配和容错。未选择的每个端点的成本仅限于接收和处理IHello,以及生成和发送RHello。

In one circumstance, multiple servers of similar processing and networking capacity may be located in near proximity to each other, such as in a data center. In this circumstance, a less heavily loaded server can respond to an IHello more quickly than more heavily loaded servers and will tend to be selected by a client.

在一种情况下,具有类似处理和联网能力的多个服务器可以彼此靠近,例如在数据中心中。在这种情况下,负载较轻的服务器可以比负载较重的服务器更快地响应IHello,并且倾向于由客户端选择。

In another circumstance, multiple servers may be located in different physical locations, such as different data centers. In this circumstance, a server that is located nearer (in terms of network distance) to the client can respond earlier than more distant servers and will tend to be selected by the client.

在另一种情况下,多台服务器可能位于不同的物理位置,例如不同的数据中心。在这种情况下,距离客户机较近(就网络距离而言)的服务器可以比距离较远的服务器更早响应,并且倾向于由客户机选择。

Multiple servers, in proximity or distant from one another, can form a redundant pool of servers. A client can perform a parallel open to the multiple servers. In normal operation, the multiple servers will all respond, and the client will select one of them as described above. If one of the multiple servers fails, other servers in the pool can still respond to the client, allowing the client to succeed to an S_OPEN session with one of them.

多台服务器彼此靠近或远离,可以形成一个冗余的服务器池。客户端可以对多个服务器执行并行开放。在正常操作中,多个服务器都将响应,客户端将如上所述选择其中一个。如果多台服务器中的一台出现故障,池中的其他服务器仍然可以响应客户端,从而允许客户端成功地与其中一台服务器进行S_OPEN会话。

3.5.2. Congestion Control
3.5.2. 拥塞控制

An RTMFP MUST implement congestion control and avoidance algorithms that are "TCP compatible", in accordance with Internet best current practice [RFC2914]. The algorithms SHOULD NOT be more aggressive in sending data than those described in "TCP Congestion Control" [RFC5681] and MUST NOT be more aggressive in sending data than the "slow start algorithm" described in Section 3.1 of RFC 5681.

RTMFP必须根据互联网最佳实践[RFC2914]实施“TCP兼容”的拥塞控制和避免算法。这些算法在发送数据时不应比“TCP拥塞控制”[RFC5681]中所述的算法更激进,在发送数据时也不应比RFC 5681第3.1节中所述的“慢启动算法”更激进。

An endpoint maintains a transmission budget in the session information context of each S_OPEN session (Section 3.5), controlling the rate at which the endpoint sends data into the network.

端点在每个S_开放会话(第3.5节)的会话信息上下文中维护传输预算,控制端点向网络发送数据的速率。

For window-based congestion control and avoidance algorithms, the transmission budget is the congestion window, which is the amount of user data that is allowed to be outstanding, or in flight, in the network. Transmission is allowed when S_OUTSTANDING_BYTES (Section 3.5) is less than the congestion window (Section 3.6.2.3). See Appendix A for an experimental window-based congestion control algorithm for real-time and bulk data.

对于基于窗口的拥塞控制和避免算法,传输预算是拥塞窗口,即允许在网络中未完成或正在传输的用户数据量。当S_字节(第3.5节)小于拥塞窗口(第3.6.2.3节)时,允许传输。有关实时和批量数据的基于窗口的拥塞控制算法的实验,请参见附录A。

An endpoint avoids sending large bursts of data or packets into the network (Section 3.5.2.3).

端点避免向网络发送大量数据或数据包(第3.5.2.3节)。

A sending endpoint increases and decreases its transmission budget in response to acknowledgements (Section 3.6.2.4) and loss according to the congestion control and avoidance algorithms. Loss is detected by negative acknowledgement (Section 3.6.2.5) and timeout (Section 3.6.2.6).

发送端点根据拥塞控制和避免算法增加和减少其传输预算,以响应确认(第3.6.2.4节)和丢失。通过否定确认(第3.6.2.5节)和超时(第3.6.2.6节)检测丢失。

Timeout is determined by the Effective Retransmission Timeout (ERTO) (Section 3.5.2.2). The ERTO is measured using the Timestamp and Timestamp Echo packet header fields (Section 2.2.4).

超时由有效重传超时(ERTO)确定(第3.5.2.2节)。ERTO使用时间戳和时间戳回波数据包报头字段测量(第2.2.4节)。

A receiving endpoint acknowledges all received data (Section 3.6.3.4) to enable the sender to measure receipt of data, or lack thereof.

接收端点确认所有接收到的数据(第3.6.3.4节),以使发送方能够测量数据的接收或缺少。

A receiving endpoint may be receiving time critical (or real-time) data from a first sender while receiving data from other senders. The receiving endpoint can signal its other senders (Section 2.2.4)

接收端点可以从第一发送方接收时间关键(或实时)数据,同时从其他发送方接收数据。接收端可以向其其他发送方发送信号(第2.2.4节)

to cause them to decrease the aggressiveness of their congestion control and avoidance algorithms, in order to yield network capacity to the time critical data (Section 3.5.2.1).

使他们降低拥塞控制和避免算法的攻击性,以便为时间关键型数据提供网络容量(第3.5.2.1节)。

3.5.2.1. Time Critical Reverse Notification
3.5.2.1. 时间关键型反向通知

A sender can increase its transmission budget at a rate compatible with (but not exceeding) the "slow start algorithm" specified in RFC 5681 (with which the transmission rate is doubled every round trip when beginning or restarting transmission, until loss is detected). However, a sender MUST behave as though the slow start threshold SSTHRESH is clamped to 0 (disabling the slow start algorithm's exponential increase behavior) on a session where a Time Critical Reverse Notification (Section 2.2.4) indication has been received from the far end within the last 800 milliseconds, unless the sender is itself currently sending time critical data to the far end.

发送方可以以与RFC 5681中规定的“慢启动算法”兼容(但不超过该算法)的速率增加其传输预算(在检测到丢失之前,在开始或重新启动传输时,每往返一次,传输速率将加倍)。但是,在最近800毫秒内从远端接收到时间关键型反向通知(第2.2.4节)指示的会话中,发送方的行为必须如同慢速启动阈值SSTHRESH被钳制为0(禁用慢速启动算法的指数增长行为)一样,除非发送方自身当前正在向远端发送时间关键型数据。

During each round trip, a sender SHOULD NOT increase the transmission budget by more than 0.5% or by 384 bytes per round trip (whichever is greater) on a session where a Time Critical Reverse Notification indication has been received from the far end within the last 800 milliseconds, unless the sender is itself currently sending time critical data to the far end.

在每次往返过程中,如果在最近800毫秒内从远端接收到时间关键型反向通知指示,则发送方不应在每次往返过程中将传输预算增加超过0.5%或384字节(以较大者为准),除非发送方自身当前正在向远端发送时间关键型数据。

3.5.2.2. Retransmission Timeout
3.5.2.2. 重传超时

RTMFP uses the ERTO to detect when a user data fragment has been lost in the network. The ERTO is typically calculated in a manner similar to that specified in "Requirements for Internet Hosts - Communication Layers" [RFC1122] and is a function of round-trip time measurements and persistent timeout behavior.

RTMFP使用ERTO来检测用户数据片段何时在网络中丢失。ERTO通常以类似于“互联网主机要求-通信层”[RFC1122]中规定的方式计算,是往返时间测量和持续超时行为的函数。

The ERTO SHOULD be at least 250 milliseconds and SHOULD allow for the receiver to delay sending an acknowledgement for up to 200 milliseconds (Section 3.6.3.4.4). The ERTO MUST NOT be less than the round-trip time.

ERTO应至少为250毫秒,且应允许接收器延迟发送确认达200毫秒(第3.6.3.4.4节)。ERTO不得小于往返时间。

To facilitate round-trip time measurement, an endpoint MUST implement the Timestamp Echo facility:

为了便于往返时间测量,端点必须实现时间戳回送功能:

o On a session entering the S_OPEN state, initialize TS_RX_TIME to negative infinity, and initialize TS_RX and TS_ECHO_TX to have no value.

o 在会话进入S_打开状态时,将TS_RX_时间初始化为负无穷大,并将TS_RX和TS_ECHO_TX初始化为无值。

o On receipt of a packet in an S_OPEN session with the timestampPresent (Section 2.2.4) flag set, if the timestamp field in the packet is different than TS_RX, set TS_RX to the value of the timestamp field in the packet, and set TS_RX_TIME to the current time.

o 在设置了timestampPresent(第2.2.4节)标志的S_OPEN会话中接收到数据包时,如果数据包中的时间戳字段不同于TS_RX,则将TS_RX设置为数据包中时间戳字段的值,并将TS_RX_TIME设置为当前时间。

o When sending a packet to the far end in an S_OPEN session:

o 在S_OPEN会话中将数据包发送到远端时:

1. Calculate TS_RX_ELAPSED = current time - TS_RX_TIME. If TS_RX_ELAPSED is more than 128 seconds, then set TS_RX and TS_ECHO_TX to have no value, and do not include a timestamp echo; otherwise,

1. 计算TS_RX_经过的时间=当前时间-TS_RX_时间。如果TS_RX_经过的时间超过128秒,则将TS_RX和TS_ECHO_TX设置为无值,并且不包括时间戳ECHO;否则

2. Calculate TS_RX_ELAPSED_TICKS to be the number of whole 4-millisecond periods in TS_RX_ELAPSED; then

2. 计算TS_RX_经过的时间间隔为TS_RX_经过的整个4毫秒周期数;然后

3. Calculate TS_ECHO = (TS_RX + TS_RX_ELAPSED_TICKS) MODULO 65536; then

3. 计算TS_ECHO=(TS_RX+TS_RX_经过的滴答声)模65536;然后

4. If TS_ECHO is not equal to TS_ECHO_TX, then set TS_ECHO_TX to TS_ECHO, set the timestampEchoPresent flag, and set the timestampEcho field to TS_ECHO_TX.

4. 如果TS_ECHO不等于TS_ECHO_TX,则将TS_ECHO_TX设置为TS_ECHO,设置timestampechospresent标志,并将timestampEcho字段设置为TS_ECHO_TX。

The remainder of this section describes an OPTIONAL method for calculating the ERTO. Real-time applications and P2P mesh applications often require knowing the round-trip time and RTT variance. This section additionally describes a method for measuring the round-trip time and RTT variance, and calculating a smoothed round-trip time.

本节剩余部分介绍了计算ERTO的可选方法。实时应用程序和P2P网格应用程序通常需要知道往返时间和RTT方差。本节还描述了测量往返时间和RTT方差以及计算平滑往返时间的方法。

Let the session information context contain additional variables:

让会话信息上下文包含其他变量:

o TS_TX: the last timestamp sent to the far end, initialized to have no value;

o TS_TX:发送到远端的最后一个时间戳,初始化为无值;

o TS_ECHO_RX: the last timestamp echo received from the far end, initialized to have no value;

o TS_ECHO_RX:从远端接收的最后一个时间戳ECHO,初始化为无值;

o SRTT: the smoothed round-trip time, initialized to have no value;

o SRTT:平滑往返时间,初始化为无值;

o RTTVAR: the round-trip time variance, initialized to 0.

o RTTVAR:往返时间差异,初始化为0。

Initialize MRTO to 250 milliseconds.

将MRTO初始化为250毫秒。

Initialize ERTO to 3 seconds.

将ERTO初始化为3秒。

On sending a packet to the far end of an S_OPEN session, if the current send timestamp is not equal to TS_TX, then set TS_TX to the current send timestamp, set the timestampPresent flag in the packet header, and set the timestamp field to TS_TX.

将数据包发送到S_开放会话的远端时,如果当前发送时间戳不等于TS_TX,则将TS_TX设置为当前发送时间戳,在数据包头中设置timestampPresent标志,并将时间戳字段设置为TS_TX。

On receipt of a packet from the far end of an S_OPEN session, if the timestampEchoPresent flag is set in the packet header, AND the timestampEcho field is not equal to TS_ECHO_RX, then:

在从S_开放会话的远端接收到数据包时,如果在数据包报头中设置了timestampEchoPresent标志,并且timestampEcho字段不等于TS_ECHO_RX,则:

1. Set TS_ECHO_RX to timestampEcho;

1. 将TS_ECHO_RX设置为timestampEcho;

2. Calculate RTT_TICKS = (current send timestamp - timestampEcho) MODULO 65536;

2. 计算RTT_TICKS=(当前发送时间戳-时间戳回波)模65536;

3. If RTT_TICKS is greater than 32767, the measurement is invalid, so discard this measurement; otherwise,

3. 如果RTT_TICKS大于32767,则测量值无效,因此放弃该测量值;否则

4. Calculate RTT = RTT_TICKS * 4 milliseconds;

4. 计算RTT=RTT_TICKS*4毫秒;

5. If SRTT has a value, then calculate new values of RTTVAR and SRTT:

5. 如果SRTT有一个值,则计算RTTVAR和SRTT的新值:

1. RTT_DELTA = | SRTT - RTT |;

1. RTT|u DELTA=| SRTT-RTT |;

2. RTTVAR = ((3 * RTTVAR) + RTT_DELTA) / 4;

2. RTTVAR=((3*RTTVAR)+RTT_DELTA)/4;

3. SRTT = ((7 * SRTT) + RTT) / 8.

3. SRTT=((7*SRTT)+RTT)/8。

6. If SRTT has no value, then set SRTT = RTT and RTTVAR = RTT / 2;

6. 如果SRTT没有值,则设置SRTT=RTT,RTTVAR=RTT/2;

7. Set MRTO = SRTT + 4 * RTTVAR + 200 milliseconds;

7. 设置MRTO=SRTT+4*RTTVAR+200毫秒;

8. Set ERTO to MRTO or 250 milliseconds, whichever is greater.

8. 将ERTO设置为MRTO或250毫秒,以较大者为准。

A retransmission timeout occurs when the most recently transmitted user data fragment has remained outstanding in the network for ERTO. When this timeout occurs, increase ERTO on an exponential backoff with an ultimate backoff cap of 10 seconds:

当最近传输的用户数据片段在网络中为ERTO保持未处理状态时,会发生重传超时。发生此超时时,在指数退避时增加ERTO,最终退避上限为10秒:

1. Calculate ERTO_BACKOFF = ERTO * 1.4142;

1. 计算ERTO_回退=ERTO*1.4142;

2. Calculate ERTO_CAPPED to be ERTO_BACKOFF or 10 seconds, whichever is less;

2. 计算ERTO_上限为ERTO_后退或10秒,以较小者为准;

3. Set ERTO to ERTO_CAPPED or MRTO, whichever is greater.

3. 将ERTO设置为ERTO_或MRTO,以较大者为准。

3.5.2.3. Burst Avoidance
3.5.2.3. 突发避免

An application's sending patterns may cause the transmission budget to grow to a large value, but at times its sending patterns will result in a comparatively small amount of data outstanding in the network. In this circumstance, especially with a window-based congestion avoidance algorithm, if the application then has a large amount of new data to send (for example, a new bulk data transfer), it could send data into the network all at once to fill the window. This kind of transmission burst is undesirable, however, because it can jam interfaces, links, and buffers.

应用程序的发送模式可能会导致传输预算增加到一个较大的值,但有时其发送模式会导致网络中未完成的数据量相对较小。在这种情况下,尤其是使用基于窗口的拥塞避免算法时,如果应用程序随后有大量新数据要发送(例如,新的批量数据传输),则它可以一次将数据发送到网络以填充窗口。然而,这种传输突发是不可取的,因为它会阻塞接口、链路和缓冲区。

Accordingly, in any session, an endpoint SHOULD NOT send more than six packets containing user data between receiving any acknowledgements or retransmission timeouts.

因此,在任何会话中,端点在接收任何确认或重传超时之间不应发送超过六个包含用户数据的分组。

The following describes an OPTIONAL method to avoid bursting large numbers of packets into the network:

以下描述了避免大量数据包涌入网络的可选方法:

Let the session information context contain an additional variable DATA_PACKET_COUNT, initialized to 0.

让会话信息上下文包含一个额外的变量DATA\u PACKET\u COUNT,初始化为0。

Transmission of a user data fragment on this session is not allowed if DATA_PACKET_COUNT is greater than or equal to 6, regardless of any other allowance of the congestion control algorithm.

如果数据包计数大于或等于6,则不允许在此会话上传输用户数据片段,而不管拥塞控制算法的任何其他允许。

On transmission of a packet containing at least one User Data chunk (Section 2.3.11), set DATA_PACKET_COUNT = DATA_PACKET_COUNT + 1.

在传输包含至少一个用户数据块的数据包时(第2.3.11节),设置数据包计数=数据包计数+1。

On receipt of an acknowledgement chunk (Sections 2.3.13 and 2.3.14), set DATA_PACKET_COUNT to 0.

收到确认数据块(第2.3.13节和第2.3.14节)后,将数据包计数设置为0。

On a retransmission timeout, set DATA_PACKET_COUNT to 0.

在重新传输超时时,将数据包计数设置为0。

3.5.3. Address Mobility
3.5.3. 地址移动性

Sessions are demultiplexed with a 32-bit session ID, rather than by endpoint address. This allows an endpoint's address to change during an S_OPEN session. This can happen, for example, when switching from a wireless to a wired network, or when moving from one wireless base station to another, or when a NAT restarts.

会话使用32位会话ID(而不是端点地址)解复用。这允许端点的地址在s_打开会话期间更改。例如,当从无线网络切换到有线网络时,或者当从一个无线基站移动到另一个无线基站时,或者当NAT重新启动时,可能会发生这种情况。

If the near end receives a valid packet for an S_OPEN session from a source address that doesn't match DESTADDR, the far end might have changed addresses. The near end SHOULD verify that the far end is definitively at the new address before changing DESTADDR. A suggested verification method is described in Section 3.5.4.2.

如果近端从与DESTADDR不匹配的源地址接收到S_开放会话的有效数据包,则远端可能已更改地址。在更改DESTADDR之前,近端应验证远端是否位于新地址。第3.5.4.2节描述了建议的验证方法。

3.5.4. Ping
3.5.4. 发出砰的声响

If an endpoint receives a Ping chunk (Section 2.3.9) in a session in the S_OPEN state, it SHOULD construct and send a Ping Reply chunk (Section 2.3.10) in response if possible, copying the message unaltered. The Ping Reply SHOULD be sent as quickly as possible following receipt of a Ping. The semantics of a Ping's message is reserved for the sender; a receiver SHOULD NOT interpret the Ping's message.

如果端点在S_OPEN状态下的会话中接收到Ping块(第2.3.9节),则应尽可能构造并发送Ping应答块(第2.3.10节)作为响应,复制消息时不作更改。收到Ping后,应尽快发送Ping回复。Ping消息的语义保留给发送方;接收者不应解释Ping的消息。

Endpoints can use the mechanism of the Ping chunk and the expected Ping Reply for any purpose. This specification doesn't mandate any specific constraints on the format or semantics of a Ping message. A Ping Reply MUST be sent only as a response to a Ping.

端点可以将Ping块和预期的Ping应答机制用于任何目的。本规范不要求对Ping消息的格式或语义有任何特定的约束。Ping回复只能作为对Ping的响应发送。

Receipt of a Ping Reply implies live bidirectional connectivity. This specification doesn't mandate any other semantics for a Ping Reply.

收到Ping回复意味着实时双向连接。本规范不要求Ping回复具有任何其他语义。

3.5.4.1. Keepalive
3.5.4.1. 保持活力

An endpoint can use a Ping to test for live bidirectional connectivity, to test that the far end of a session is still in the S_OPEN state, to keep NAT translations alive, and to keep firewall holes open.

端点可以使用Ping来测试实时双向连接,测试会话的远端是否仍处于S_OPEN状态,保持NAT转换活动,以及保持防火墙漏洞打开。

An endpoint can use a Ping to hasten detection of a near-end address change by the far end.

端点可以使用Ping来加速检测远端的近端地址更改。

An endpoint may declare a session to be defunct and dead after a persistent failure by the far end to return Ping Replies in response to Pings.

端点可以在远端持续失败以返回Ping回复以响应Ping之后,将会话声明为失效和死会话。

If used for these purposes, a Keepalive Ping SHOULD have an empty message.

如果用于这些目的,Keepalive Ping应该有一条空消息。

A Keepalive Ping SHOULD NOT be sent more often than once per ERTO. If a corresponding Ping Reply is not received within ERTO of sending the Ping, ERTO SHOULD be increased according to Section 3.5.2 ("Congestion Control").

Keepalive Ping的发送频率不应超过每次一次。如果在发送Ping的ERTO内未收到相应的Ping回复,则应根据第3.5.2节(“拥塞控制”)增加ERTO。

3.5.4.2. Address Mobility
3.5.4.2. 地址移动性

This section describes an OPTIONAL but suggested method for processing and verifying a far-end address change.

本节介绍一种可选但建议的方法,用于处理和验证远端地址更改。

Let the session context contain additional variables MOB_TX_TS, MOB_RX_TS, and MOB_SECRET. MOB_TX_TS and MOB_RX_TS have initial values of negative infinity. MOB_SECRET should be a cryptographically pseudorandom value not less than 128 bits in length and known only to this end.

让会话上下文包含其他变量MOB_TX_TS、MOB_RX_TS和MOB_SECRET。MOB_TX_TS和MOB_RX_TS的初始值为负无穷大。MOB_SECRET应该是一个长度不小于128位的加密伪随机值,并且只有在这方面才知道。

On receipt of a packet for an S_OPEN session, after processing all chunks in the packet: if the session is still in the S_OPEN state, AND the source address of the packet does not match DESTADDR, AND MOB_TX_TS is at least one second in the past, then:

在接收到S_OPEN会话的数据包后,在处理数据包中的所有数据块后:如果会话仍处于S_OPEN状态,且数据包的源地址与DESTADDR不匹配,并且MOB_TX_TS过去至少为1秒,则:

1. Set MOB_TX_TS to the current time;

1. 将移动发送设置为当前时间;

2. Construct a Ping message comprising the following: a marking to indicate (to this end when returned in a Ping Reply) that it is a mobility check (for example, the first byte being ASCII 'M' for "Mobility"), a timestamp set to MOB_TX_TS, and a cryptographic hash over the following: the preceding items, the address from which the packet was received, and MOB_SECRET; and

2. 构造一个Ping消息,包括以下内容:一个标记,用于指示(在Ping应答中返回时)它是一个移动性检查(例如,第一个字节是ASCII'M'表示“移动性”)、一个设置为MOB_TX_TS的时间戳,以及以下内容的加密散列:前面的项目、接收数据包的地址,还有暴徒的秘密;和

3. Send this Ping to the address from which the packet was received, instead of DESTADDR.

3. 将此Ping发送到接收数据包的地址,而不是DESTADDR。

On receipt of a Ping Reply in an S_OPEN session, if the Ping Reply's message satisfies all of these conditions:

在S_OPEN会话中收到Ping回复后,如果Ping回复的消息满足所有这些条件:

o it has this end's expected marking to indicate that it is a mobility check, and

o 它有这一端的预期标记,以表明它是一个移动性检查,以及

o the timestamp in the message is not more than 120 seconds in the past, and

o 消息中的时间戳过去不超过120秒,并且

o the timestamp in the message is greater than MOB_RX_TS, and

o 消息中的时间戳大于MOB_RX_TS,并且

o the cryptographic hash matches the expected value according to the contents of the message plus the source address of the packet containing this Ping Reply and MOB_SECRET,

o 加密散列根据消息内容加上包含此Ping应答和MOB_秘密的数据包的源地址匹配预期值,

then:

然后:

1. Set MOB_RX_TS to the timestamp in the message; and

1. 将MOB_RX_TS设置为消息中的时间戳;和

2. Set DESTADDR to the source address of the packet containing this Ping Reply.

2. 将DESTADDR设置为包含此Ping应答的数据包的源地址。

3.5.4.3. Path MTU Discovery
3.5.4.3. 路径MTU发现

"Packetization Layer Path MTU Discovery" [RFC4821] describes a method for measuring the path MTU between communicating endpoints.

“打包层路径MTU发现”[RFC4821]描述了一种测量通信端点之间路径MTU的方法。

An RTMFP SHOULD perform path MTU discovery.

RTMFP应执行路径MTU发现。

The method described in RFC 4821 can be adapted for use in RTMFP by sending a probe packet comprising one of the Padding chunk types (type 0x00 or 0xff) and a Ping. The Ping chunk SHOULD come after the Padding chunk, to guard against a false positive response in case the probe packet is truncated.

RFC 4821中描述的方法可以通过发送包含填充块类型(类型0x00或0xff)和Ping中的一种的探测包来适于在RTMFP中使用。Ping块应该位于Padding块之后,以防止探测数据包被截断时出现误报响应。

3.5.5. Close
3.5.5. 关

An endpoint may close a session at any time. Typically, an endpoint will close a session when there have been no open flows in either direction for a time. In another circumstance, an endpoint may be ceasing operation and will close all of its sessions even if they have open flows.

端点可以随时关闭会话。通常,当任一方向上都有一段时间没有开放流时,端点将关闭会话。在另一种情况下,端点可能正在停止操作,并将关闭其所有会话,即使它们具有开放的流。

To close an S_OPEN session in a reliable and orderly fashion, an endpoint moves the session to the S_NEARCLOSE state.

要以可靠且有序的方式关闭S_OPEN会话,端点会将会话移动到S_NEARCLOSE状态。

On a session transitioning from S_OPEN to S_NEARCLOSE and every 5 seconds thereafter while still in the S_NEARCLOSE state, send a Session Close Request chunk (Section 2.3.17).

在会话从S_OPEN转换为S_NEARCLOSE时,以及此后每5秒仍处于S_NEARCLOSE状态时,发送会话关闭请求块(第2.3.17节)。

A session that has been in the S_NEARCLOSE state for at least 90 seconds (allowing time to retransmit the Session Close Request multiple times) SHOULD move to the S_CLOSED state.

处于S_NEARCLOSE状态至少90秒(允许时间多次重新传输会话关闭请求)的会话应移动到S_Close状态。

On a session transitioning from S_OPEN to the S_NEARCLOSE, S_FARCLOSE_LINGER or S_CLOSED state, immediately abort and terminate all open or closing flows. Flows only exist in S_OPEN sessions.

在会话从S_OPEN转换到S_NEARCLOSE、S_FARCLOSE或S_CLOSED状态时,立即中止并终止所有打开或关闭流。流仅存在于S_开放会话中。

To close an S_OPEN session abruptly, send a Session Close Acknowledgement chunk (Section 2.3.18), then move to the S_CLOSED state.

要突然关闭S_OPEN会话,请发送会话关闭确认块(第2.3.18节),然后移动到S_CLOSED状态。

On receipt of a Session Close Request chunk for a session in the S_OPEN, S_NEARCLOSE, or S_FARCLOSE_LINGER states, send a Session Close Acknowledgement chunk; then, if the session is in the S_OPEN state, move to the S_FARCLOSE_LINGER state.

在收到S_OPEN、S_NEARCLOSE或S_FARCLOSE_LINGER状态下会话的会话关闭请求区块后,发送会话关闭确认区块;然后,如果会话处于S_OPEN状态,则移动到S_FARCLOSE_LINGER状态。

A session that has been in the S_FARCLOSE_LINGER state for at least 19 seconds (allowing time to answer 3 retransmissions of a Session Close Request) SHOULD move to the S_CLOSED state.

处于S_FARCLOSE_LINGER状态至少19秒的会话(允许有时间回答会话关闭请求的3次重传)应移动到S_CLOSED状态。

On receipt of a Session Close Acknowledgement chunk for a session in the S_OPEN, S_NEARCLOSE, or S_FARCLOSE_LINGER states, move to the S_CLOSED state.

在收到S_OPEN、S_NEARCLOSE或S_FARCLOSE_LINGER状态下会话的会话关闭确认块后,移动到S_CLOSED状态。

3.6. Flows
3.6. 流动

A flow is a unidirectional communication channel in a session for transporting a correlated series of user messages from a sender to a receiver. Each end of a session may have zero or more sending flows to the other end. Each sending flow at one end has a corresponding receiving flow at the other end.

流是会话中的单向通信信道,用于将一系列相关的用户消息从发送方传输到接收方。会话的每一端可能有零个或多个发送流到另一端。一端的每个发送流在另一端具有相应的接收流。

3.6.1. Overview
3.6.1. 概述
3.6.1.1. Identity
3.6.1.1. 身份

Flows are multiplexed in a session by a flow identifier. Each end of a session chooses its sending flow identifiers independently of the other end. The choice of similar flow identifiers by both ends does not imply an association. A sender MAY choose any identifier for any flow; therefore, a flow receiver MUST NOT ascribe any semantic meaning, role, or name to a flow based only on its identifier. There are no "well known" or reserved flow identifiers.

流通过流标识符在会话中多路复用。会话的每一端独立于另一端选择其发送流标识符。两端选择相似的流标识符并不意味着关联。发送方可以为任何流选择任何标识符;因此,流接收者不得仅基于其标识符将任何语义、角色或名称赋予流。没有“已知”或保留的流标识符。

Bidirectional flow association is indicated at flow startup with the Return Flow Association option (Section 2.3.11.1.2). An endpoint can indicate that a new sending flow is in return (or response) to a receiving flow from the other end. A sending flow MUST NOT indicate more than one return association. A receiving flow can be specified as the return association for any number of sending flows. The return flow association, if any, is fixed for the lifetime of the sending flow. Note: Closure of one flow in an association does not automatically close other flows in the association, except as specified in Section 3.6.3.1.

双向流量关联在流量启动时用回流关联选项指示(第2.3.11.1.2节)。端点可以指示新的发送流返回(或响应)另一端的接收流。发送流不能指示多个返回关联。可以将接收流指定为任意数量的发送流的返回关联。返回流关联(如果有)在发送流的生存期内是固定的。注:关闭关联中的一个流不会自动关闭关联中的其他流,除非第3.6.3.1节另有规定。

Flows are named with arbitrary user metadata. This specification doesn't mandate any particular encoding, syntax, or semantics for the user metadata, except for the encoded size (Section 2.3.11.1.1); the user metadata is entirely reserved for the application. The user metadata is fixed for the lifetime of the flow.

流使用任意用户元数据命名。除编码大小(第2.3.11.1.1节)外,本规范不要求用户元数据有任何特定的编码、语法或语义;用户元数据完全保留给应用程序。用户元数据在流的生命周期内是固定的。

3.6.1.2. Messages and Sequencing
3.6.1.2. 信息和排序

Flows provide message-oriented framing. Large messages are fragmented for transport in the network. Receivers reassemble fragmented messages and only present complete messages to the user.

流提供面向消息的框架。大型消息被分割,以便在网络中传输。接收者重新组合零碎的消息,只向用户呈现完整的消息。

A sender queues messages on a sending flow one after another. A receiver can recover the original queuing order of the messages, even when they are reordered in transit by the network or as a result of loss and retransmission, by means of the messages' fragment sequence numbers. Flows are the basic units of message sequencing; each flow is sequenced independently of all other flows; inter-flow message arrival and delivery sequencing are not guaranteed.

发送者在发送流上一个接一个地将消息排队。接收方可以通过消息的片段序列号恢复消息的原始排队顺序,即使它们在传输过程中被网络重新排序,或者由于丢失和重新传输而重新排序。流是消息排序的基本单元;每个流独立于所有其他流进行排序;不保证流间消息到达和传递顺序。

Independent flow sequencing allows a sender to prioritize the transmission or retransmission of the messages of one flow over those of other flows in a session, allocating capacity from the transmission budget according to priority. RTMFP is designed for flows to be the basic unit of prioritization. In any flow, fragment sequence numbers are unique and monotonically increasing; that is, the fragment sequence numbers for any message MUST be greater than the fragment sequence numbers of all messages previously queued in that flow. Receipt of fragments out of sequence number order within a flow creates discontiguous gaps at the receiver, causing it to send an acknowledgement for every packet and also causing the size of the encoded acknowledgements to grow. Therefore, for any flow, the sender SHOULD send lower sequence numbers first.

独立流排序允许发送方将会话中一个流的消息的传输或重传优先于其他流的消息的传输或重传,并根据优先级从传输预算中分配容量。RTMFP设计用于将流作为优先级的基本单位。在任何流中,片段序列号都是唯一且单调递增的;也就是说,任何消息的片段序列号必须大于先前在该流中排队的所有消息的片段序列号。在流中按顺序接收片段会在接收器处产生不连续的间隙,导致接收器发送每个数据包的确认,并且导致编码确认的大小增加。因此,对于任何流,发送方都应该首先发送较低的序列号。

A sender can abandon a queued message at any time, even if some fragments of that message have been received by the other end. A receiver MUST be able to detect a gap in the flow when a message is abandoned; therefore, each message SHOULD take at least one sequence number from the sequence space even if no fragments for that message are ever sent. The sender will transmit the fragments of all messages not abandoned, and retransmit any lost fragments of all messages not abandoned, until all the fragments of all messages not abandoned are acknowledged by the receiver. A sender indicates a Forward Sequence Number (FSN) to instruct the receiver that sequence numbers less than or equal to the FSN will not be transmitted or retransmitted. This allows the receiver to move forward over gaps and continue sequenced delivery of completely received messages to the user. Any incomplete messages missing fragments with sequence

发送方可以随时放弃排队的消息,即使该消息的某些片段已被另一端接收。当消息被放弃时,接收器必须能够检测到流中的间隙;因此,每个消息应该至少从序列空间中获取一个序列号,即使从未发送过该消息的片段。发送方将传输所有未放弃消息的片段,并重新传输所有未放弃消息的任何丢失片段,直到接收方确认所有未放弃消息的所有片段。发送方指示前向序列号(FSN),以指示接收方不发送或重传小于或等于FSN的序列号。这允许接收者在间隙中向前移动,并继续将完全接收到的消息按顺序传递给用户。任何不完整的消息都缺少具有序列的片段

numbers less than or equal to the FSN were abandoned by the sender and will never be completed. A gap indication MUST be communicated to the receiving user.

小于或等于FSN的号码已被发件人放弃,并且将永远无法完成。间隙指示必须传达给接收用户。

3.6.1.3. Lifetime
3.6.1.3. 一生

A sender begins a flow by sending user message fragments to the other end, and including the user metadata and, if any, the return flow association. The sender continues to include the user metadata and return flow association until the flow is acknowledged by the far end, at which point the sender knows that the receiver has received the user metadata and, if any, the return flow association. After that point, the flow identifier alone is sufficient.

发送方通过向另一端发送用户消息片段开始流,包括用户元数据和返回流关联(如果有)。发送方继续包括用户元数据和返回流关联,直到远端确认该流,此时发送方知道接收方已收到用户元数据和返回流关联(如果有)。在该点之后,仅流标识符就足够了。

Flow receivers SHOULD acknowledge all sequence numbers received for any flow, whether the flow is accepted or rejected. Flow receivers MUST NOT acknowledge sequence numbers higher than the FSN that were not received. Acknowledgements drive the congestion control and avoidance algorithms and therefore must be accurate.

流量接收器应确认接收到的任何流量的所有序列号,无论该流量是否被接受。流量接收器不得确认高于未接收的FSN的序列号。确认驱动拥塞控制和避免算法,因此必须准确。

An endpoint can reject a receiving flow at any time in the flow's lifetime. To reject the flow, the receiving endpoint sends a Flow Exception Report chunk (Section 2.3.16) immediately preceding every acknowledgement chunk for the rejected receiving flow.

端点可以在流生命周期中的任何时间拒绝接收流。为了拒绝流,接收端点在被拒绝的接收流的每个确认块之前发送一个流异常报告块(第2.3.16节)。

An endpoint may eventually conclude and close a sending flow. The last sequence number of the flow is marked with the Final flag. The sending flow is complete when all sequence numbers of the flow, including the final sequence number, have been cumulatively acknowledged by the receiver. The receiving flow is complete when every sequence number from the FSN to the final sequence number has been received. The sending flow and corresponding receiving flow at the respective ends hold the flow identifier of a completed flow in reserve for a time to allow delayed or duplicated fragments and acknowledgements to drain from the network without erroneously initiating a new receiving flow or erroneously acknowledging a new sending flow.

端点可能最终结束并关闭发送流。流的最后一个序列号用Final标志标记。当流的所有序列号(包括最终序列号)已被接收器累积确认时,发送流完成。当接收到从FSN到最终序列号的每个序列号时,接收流程完成。各端的发送流和相应的接收流将已完成流的流标识符保留一段时间,以允许延迟或重复的片段和确认从网络中排出,而不会错误地启动新的接收流或错误地确认新的发送流。

If a flow sender receives a Flow Exception indication from the other end, the flow sender SHOULD close the flow and abandon all of the undelivered queued messages. The flow sender SHOULD indicate an exception to the user.

如果流发送方从另一端接收到流异常指示,则流发送方应关闭流并放弃所有未送达的排队消息。流发送器应向用户指示异常。

3.6.2. Sender
3.6.2. 发件人

Each sending flow comprises the flow-specific information context necessary to transfer that flow's messages to the other end. Each sending flow context includes at least:

每个发送流包含将该流的消息传输到另一端所需的流特定信息上下文。每个发送流上下文至少包括:

o F_FLOW_ID: this flow's identifier;

o F_FLOW_ID:此流的标识符;

o STARTUP_OPTIONS: the set of options to send to the receiver until this flow is acknowledged, including the User's Per-Flow Metadata and, if set, the Return Flow Association;

o STARTUP_OPTIONS:在确认此流之前发送给接收方的一组选项,包括用户的每流元数据和返回流关联(如果已设置);

o SEND_QUEUE: the unacknowledged message fragments queued in this flow, initially empty; each message fragment entry comprising the following:

o SEND_QUEUE:在此流中排队的未确认消息片段,最初为空;每个消息片段条目包括以下内容:

* SEQUENCE_NUMBER: the sequence number of this fragment;

* 序列号:该片段的序列号;

* DATA: this fragment's user data;

* 数据:该片段的用户数据;

* FRA: the fragment control value for this message fragment, having one of the values enumerated for that purpose in Section 2.3.11 ("User Data Chunk");

* FRA:此消息片段的片段控制值,具有第2.3.11节(“用户数据块”)中为此目的枚举的值之一;

* ABANDONED: a boolean flag indicating whether this fragment has been abandoned;

* 放弃:一个布尔标志,指示此片段是否已被放弃;

* SENT_ABANDONED: a boolean flag indicating whether this fragment was abandoned when sent;

* SENT_遗弃:一个布尔标志,指示此片段在发送时是否被遗弃;

* EVER_SENT: a boolean flag indicating whether this fragment has been sent at least once, initially false;

* EVER_SENT:一个布尔标志,指示此片段是否至少发送过一次,最初为false;

* NAK_COUNT: a count of the number of negative acknowledgements detected for this fragment, initially 0;

* NAK_COUNT:对该片段检测到的否定确认数的计数,最初为0;

* IN_FLIGHT: a boolean flag indicating whether this fragment is currently outstanding, or in flight, in the network, initially false;

* 在飞行中:一个布尔标志,指示此片段在网络中是当前未完成的,还是在飞行中,最初为false;

* TRANSMIT_SIZE: the size, in bytes, of the encoded User Data chunk (including the chunk header) for this fragment when it was transmitted into the network.

* TRANSMIT_SIZE:此片段传输到网络时的编码用户数据块(包括块头)的大小,以字节为单位。

o F_OUTSTANDING_BYTES: the sum of the TRANSMIT_SIZE of each entry in SEND_QUEUE where entry.IN_FLIGHT is true;

o F_未决_字节:entry.in_FLIGHT为真的发送队列中每个条目的传输_大小之和;

o RX_BUFFER_SIZE: the most recent available buffer advertisement from the other end (Sections 2.3.13 and 2.3.14), initially 65536 bytes;

o RX_BUFFER_SIZE:另一端最近可用的缓冲区广告(第2.3.13节和第2.3.14节),最初为65536字节;

o NEXT_SN: the next sequence number to assign to a message fragment, initially 1;

o NEXT_SN:分配给消息片段的下一个序列号,最初为1;

o F_FINAL_SN: the sequence number assigned to the final message fragment of the flow, initially having no value;

o F_FINAL_SN:分配给流的最终消息片段的序列号,最初没有值;

o EXCEPTION: a boolean flag indicating whether an exception has been reported by the receiver, initially false;

o 异常:一个布尔标志,指示接收方是否报告了异常,最初为false;

o The state, at any time being one of the following values: the open state F_OPEN; the closing states F_CLOSING and F_COMPLETE_LINGER; and the closed state F_CLOSED.

o 状态,在任何时候为以下值之一:打开状态F_open;F_closing和F_COMPLETE_LINGER的关闭状态;关闭状态fu关闭。

Note: The following diagram is only a summary of state transitions and their causing events, and is not a complete operational specification.

注意:下图只是状态转换及其导致事件的摘要,不是完整的操作规范。

                                 +--------+
                                 | F_OPEN |
                                 +--------+
                                      |CLOSE or
                                      |rcv Flow Exception
                                      |
                                      v
                                 +---------+
                                 |F_CLOSING|
                                 +---------+
                                      |rcv Data Ack
                                      |  0..F_FINAL_SN
                                      v
                             +-----------------+
                             |F_COMPLETE_LINGER|
                             +-----------------+
                                      | 130 seconds
                                      v
                                  +--------+
                                  |F_CLOSED|
                                  +--------+
        
                                 +--------+
                                 | F_OPEN |
                                 +--------+
                                      |CLOSE or
                                      |rcv Flow Exception
                                      |
                                      v
                                 +---------+
                                 |F_CLOSING|
                                 +---------+
                                      |rcv Data Ack
                                      |  0..F_FINAL_SN
                                      v
                             +-----------------+
                             |F_COMPLETE_LINGER|
                             +-----------------+
                                      | 130 seconds
                                      v
                                  +--------+
                                  |F_CLOSED|
                                  +--------+
        

Figure 19: Sending Flow State Diagram

图19:发送流状态图

3.6.2.1. Startup
3.6.2.1. 启动

The application opens a new sending flow to the other end in an S_OPEN session. The implementation chooses a new flow ID that is not assigned to any other sending flow in that session in the F_OPEN, F_CLOSING, or F_COMPLETE_LINGER states. The flow starts in the F_OPEN state. The STARTUP_OPTIONS for the new flow is set with the User's Per-Flow Metadata (Section 2.3.11.1.1). If this flow is in return (or response) to a receiving flow from the other end, that flow's ID is encoded in a Return Flow Association (Section 2.3.11.1.2) option and added to STARTUP_OPTIONS. A new sending flow SHOULD NOT be opened in response to a receiving flow from the other end that is not in the RF_OPEN state when the sending flow is opened.

应用程序在S_OPEN会话中向另一端打开一个新的发送流。在F_打开、F_关闭或F_完成状态下,实现选择一个新的流ID,该ID未分配给该会话中的任何其他发送流。流量在F_打开状态下开始。新流的启动选项由用户的每流元数据设置(第2.3.11.1.1节)。如果该流返回(或响应)来自另一端的接收流,则该流的ID将编码在返回流关联(第2.3.11.1.2节)选项中,并添加到启动选项中。当发送流打开时,另一端的接收流未处于RF_打开状态,因此不应打开新的发送流。

At this point, the flow exists in the sender but not in the receiver. The flow begins when user data fragments are transmitted to the receiver. A sender can begin a flow in the absence of immediate user data by sending a Forward Sequence Number Update (Section 3.6.2.7.1), by queuing and transmitting a user data fragment that is already abandoned.

此时,流存在于发送方,但不存在于接收方。当用户数据片段被发送到接收器时,流开始。发送方可以通过发送前向序列号更新(第3.6.2.7.1节),排队并传输已放弃的用户数据片段,在没有即时用户数据的情况下开始流。

3.6.2.2. Queuing Data
3.6.2.2. 排队数据

The application queues messages in an F_OPEN sending flow for transmission to the far end. The implementation divides each message into one or more fragments for transmission in User Data chunks (Section 2.3.11). Each fragment MUST be small enough so that, if assembled into a packet (Section 2.2.4) with a maximum-size common header, User Data chunk header, and, if not empty, this flow's STARTUP_OPTIONS, the packet will not exceed the path MTU (Section 3.5.4.3).

应用程序在F_OPEN发送流中将消息排队,以便传输到远端。该实现将每条消息分成一个或多个片段,以便在用户数据块中传输(第2.3.11节)。每个片段必须足够小,以便如果组装成具有最大大小公共头、用户数据块头的数据包(第2.2.4节),并且如果不是空的,则该流的启动_选项,该数据包将不会超过路径MTU(第3.5.4.3节)。

For each fragment, create a fragment entry and set fragmentEntry.SEQUENCE_NUMBER to flow.NEXT_SN, and increment flow.NEXT_SN by one. Set fragmentEntry.FRA according to the encoding in User Data chunks:

对于每个片段,创建一个片段条目,并将fragmentry.SEQUENCE\u NUMBER设置为flow.NEXT\u SN,并将flow.NEXT\u SN递增一。根据用户数据块中的编码设置fragmentEntry.FRA:

0: This fragment is a complete message.

0:此片段是完整的消息。

1: This fragment is the first of a multi-fragment message.

1:这个片段是多片段消息的第一个片段。

2: This fragment is the last of a multi-fragment message.

2:此片段是多片段消息的最后一个片段。

3: This fragment is in the middle of a multi-fragment message.

3:此片段位于多片段消息的中间。

Append fragmentEntry to flow.SEND_QUEUE.

将fragmentEntry追加到flow.SEND\u队列。

3.6.2.3. Sending Data
3.6.2.3. 发送数据

A sending flow is ready to transmit if the SEND_QUEUE contains at least one entry that is eligible to send, and if either RX_BUFFER_SIZE is greater than F_OUTSTANDING_BYTES or EXCEPTION is set to true.

如果发送队列包含至少一个符合发送条件的条目,并且如果RX\u BUFFER\u SIZE大于F\u未决字节或EXCEPTION设置为true,则发送流准备好发送。

A SEND_QUEUE entry is eligible to send if it is not IN_FLIGHT, AND at least one of the following conditions holds:

如果发送队列条目不在飞行中,并且至少满足以下条件之一,则该条目有资格发送:

o The entry is not ABANDONED; or

o 没有放弃入境;或

o The entry is the first one in the SEND_QUEUE; or

o 该条目是发送队列中的第一个条目;或

o The entry's SEQUENCE_NUMBER is equal to flow.F_FINAL_SN.

o 条目的序列号等于flow.F\u FINAL\u序列号。

If the session's transmission budget allows, a flow that is ready to transmit is selected for transmission according to the implementation's prioritization scheme. The manner of flow prioritization is not mandated by this specification.

如果会话的传输预算允许,则根据实现的优先级方案选择准备传输的流进行传输。本规范未强制规定流程优先级的方式。

Trim abandoned messages from the front of the queue, and find the Forward Sequence Number (FSN):

从队列前端修剪丢弃的消息,并查找转发序列号(FSN):

1. While the SEND_QUEUE contains at least two entries, AND the first entry is not IN_FLIGHT, AND the first entry is ABANDONED, remove and discard the first entry from the SEND_QUEUE;

1. 当发送队列包含至少两个条目,并且第一个条目不在发送队列中,并且第一个条目被放弃时,从发送队列中删除并放弃第一个条目;

2. If the first entry in the SEND_QUEUE is not abandoned, set FSN to entry.SEQUENCE_NUMBER - 1; otherwise,

2. 如果未放弃发送_队列中的第一个条目,请将FSN设置为entry.SEQUENCE_NUMBER-1;否则

3. If the first entry in the SEND_QUEUE is IN_FLIGHT, AND entry.SENT_ABANDONED is false, set FSN to entry.SEQUENCE_NUMBER - 1; otherwise,

3. 如果发送_队列中的第一个条目处于_飞行中,并且entry.SENT_放弃为false,则将FSN设置为entry.SEQUENCE_NUMBER-1;否则

4. The first entry in the SEND_QUEUE is abandoned and either is not IN_FLIGHT or was already abandoned when sent; set FSN to entry.SEQUENCE_NUMBER.

4. 发送队列中的第一个条目被放弃,或者不在发送队列中,或者在发送时已被放弃;将FSN设置为entry.SEQUENCE\u编号。

The FSN MUST NOT be greater than any sequence number currently outstanding. The FSN MUST NOT be equal to any sequence number currently outstanding that was not abandoned when sent.

FSN不得大于当前未完成的任何序列号。FSN不得等于发送时未放弃的当前未完成的任何序列号。

Assemble user data chunks for this flow into a packet to send to the receiver. While enough space remains in the packet and the flow is ready to transmit:

将该流的用户数据块组装成一个数据包,发送给接收方。当数据包中有足够的空间且流已准备好传输时:

1. Starting at the head of the SEND_QUEUE, find the first eligible fragment entry;

1. 从发送队列的头部开始,查找第一个符合条件的片段条目;

2. Encode the entry into a User Data chunk (Section 2.3.11) or, if possible (Section 3.6.2.3.2), a Next User Data chunk (Section 2.3.12);

2. 将条目编码到用户数据块(第2.3.11节)或下一个用户数据块(第2.3.12节),如果可能(第3.6.2.3.2节);

3. If present, set chunk.flowID to flow.F_FLOW_ID;

3. 如果存在,将chunk.flowID设置为flow.F_flow_ID;

4. If present, set chunk.sequenceNumber to entry.SEQUENCE_NUMBER;

4. 如果存在,将chunk.sequenceNumber设置为entry.SEQUENCE\u NUMBER;

5. If present, set chunk.fsnOffset to entry.SEQUENCE_NUMBER - FSN;

5. 如果存在,将chunk.fsnOffset设置为entry.SEQUENCE_NUMBER-FSN;

6. Set chunk.fragmentControl to entry.FRA;

6. 将chunk.fragmentControl设置为entry.FRA;

7. Set chunk.abandon to entry.ABANDONED;

7. 将chunk.advance设置为entry.advanced;

8. If entry.SEQUENCE_NUMBER equals flow.F_FINAL_SN, set chunk.final to true; else set chunk.final to false;

8. 如果entry.SEQUENCE\u NUMBER等于flow.F\u FINAL\u SN,则将chunk.FINAL设置为true;否则将chunk.final设置为false;

9. If any options are being sent with this chunk, set chunk.optionsPresent to true, assemble the options into the chunk, and assemble a Marker to terminate the option list;

9. 如果有任何选项与此区块一起发送,请将chunk.options present设置为true,将选项组合到区块中,然后组合一个标记以终止选项列表;

10. If entry.ABANDONED is true, set chunk.userData to empty; otherwise, set chunk.userData to entry.DATA;

10. 如果entry.advanced为true,则将chunk.userData设置为空;否则,将chunk.userData设置为entry.DATA;

11. If adding the assembled chunk to the packet would cause the packet to exceed the path MTU, do not assemble this chunk into the packet; enough space no longer remains in the packet; stop. Otherwise, continue:

11. 如果向数据包添加已组装的数据块会导致数据包超出路径MTU,则不要将该数据块组装到数据包中;数据包中不再有足够的空间;停止否则,请继续:

12. Set entry.IN_FLIGHT to true;

12. 将entry.IN_FLIGHT设置为true;

13. Set entry.EVER_SENT to true;

13. 将entry.EVER_发送到true;

14. Set entry.NAK_COUNT to 0;

14. 将entry.NAK_COUNT设置为0;

15. Set entry.SENT_ABANDONED to entry.ABANDONED;

15. 将entry.SENT\u放弃设置为entry.advanced;

16. Set entry.TRANSMIT_SIZE to the size of the assembled chunk, including the chunk header;

16. 将entry.TRANSMIT_SIZE设置为组合块的大小,包括块头;

17. Assemble this chunk into the packet; and

17. 将这一块组装到数据包中;和

18. If this flow or entry is considered Time Critical (real-time), set the timeCritical flag in the packet header (Section 2.2.4).

18. 如果此流或条目被视为时间关键型(实时),则在数据包头中设置时间关键型标志(第2.2.4节)。

Complete any other appropriate packet processing, and transmit the packet to the far end.

完成任何其他适当的数据包处理,并将数据包传输到远端。

3.6.2.3.1. Startup Options
3.6.2.3.1. 启动选项

If STARTUP_OPTIONS is not empty, then when assembling the FIRST User Data chunk for this flow into a packet, add the encoded STARTUP_OPTIONS to that chunk's option list.

如果STARTUP_OPTIONS不为空,则在将此流的第一个用户数据块组装到数据包中时,将编码的STARTUP_选项添加到该数据块的选项列表中。

3.6.2.3.2. Send Next Data
3.6.2.3.2. 发送下一个数据

The Next User Data chunk (Section 2.3.12) is a compact encoding for a user message fragment when multiple contiguous fragments are assembled into one packet. Using this chunk where possible can conserve space in a packet, potentially reducing transmission overhead or allowing additional information to be sent in a packet.

下一个用户数据块(第2.3.12节)是当多个连续片段组合成一个数据包时,用户消息片段的压缩编码。在可能的情况下使用该块可以节省数据包中的空间,从而潜在地减少传输开销或允许在数据包中发送额外的信息。

If, after assembling a user message fragment of a flow into a packet (Section 3.6.2.3), the next eligible fragment to be selected for assembly into that packet belongs to the same flow, AND its sequence number is one greater than that of the fragment just assembled, it is RECOMMENDED that an implementation encode a Next User Data chunk instead of a User Data chunk.

如果在将流的用户消息片段组装成数据包(第3.6.2.3节)后,要选择组装成该数据包的下一个合格片段属于同一个流,并且其序列号比刚刚组装的片段的序列号大一个,建议实现对下一个用户数据块而不是用户数据块进行编码。

The FIRST fragment of a flow assembled into a packet MUST be encoded as a User Data chunk.

组装成数据包的流的第一个片段必须编码为用户数据块。

3.6.2.4. Processing Acknowledgements
3.6.2.4. 处理确认

A Data Acknowledgement Bitmap chunk (Section 2.3.13) or a Data Acknowledgement Ranges chunk (Section 2.3.14) encodes the acknowledgement of receipt of one or more sequence numbers of a flow, as well as the receiver's current receive window advertisement.

数据确认位图块(第2.3.13节)或数据确认范围块(第2.3.14节)对一个或多个流序列号的接收确认以及接收器的当前接收窗口广告进行编码。

On receipt of an acknowledgement chunk for a sending flow:

在接收到发送流的确认数据块时:

1. Set PRE_ACK_OUTSTANDING_BYTES to flow.F_OUTSTANDING_BYTES;

1. 将PRE_ACK_EXTABLE_字节设置为flow.F_EXTABLE_字节;

2. Set flow.STARTUP_OPTIONS to empty;

2. 将flow.STARTUP\u选项设置为空;

3. Set flow.RX_BUFFER_SIZE to chunk.bufferBytesAvailable;

3. 将flow.RX_BUFFER_SIZE设置为chunk.bufferBytesAvailable;

4. For each sequence number encoded in the acknowledgement, if there is an entry in flow.SEND_QUEUE with that sequence number and its IN_FLIGHT is true, then remove the entry from flow.SEND_QUEUE; and

4. 对于确认中编码的每个序列号,如果flow.SEND_队列中有一个条目具有该序列号且其in_飞行为真,则从flow.SEND_队列中删除该条目;和

5. Notify the congestion control and avoidance algorithms that PRE_ACK_OUTSTANDING_BYTES - flow.F_OUTSTANDING_BYTES were acknowledged. Note that negative acknowledgements (Section 3.6.2.5) affect "TCP friendly" congestion control.

5. 通知拥塞控制和避免算法已确认PRE_ACK_未决字节-flow.F_未决字节。请注意,否定确认(第3.6.2.5节)会影响“TCP友好”拥塞控制。

3.6.2.5. Negative Acknowledgement and Loss
3.6.2.5. 否定承认与损失

A negative acknowledgement is inferred for an outstanding fragment if an acknowledgement is received for any other fragments sent after it in the same session.

如果在同一会话中接收到在未完成片段之后发送的任何其他片段的确认,则推断出未完成片段的否定确认。

An implementation SHOULD consider a fragment to be lost once that fragment receives three negative acknowledgements. A lost fragment is no longer outstanding in the network.

一旦片段接收到三个否定确认,一个实现应该考虑丢失一个片段。丢失的片段在网络中不再突出。

The following describes an OPTIONAL method for detecting negative acknowledgements.

以下描述用于检测否定确认的可选方法。

Let the session track the order in which fragments are transmitted across all its sending flows by way of a monotonically increasing Transmission Sequence Number (TSN) recorded with each fragment queue entry each time that fragment is transmitted.

让会话通过每次发送片段时记录在每个片段队列条目中的单调递增的传输序列号(TSN),跟踪片段在其所有发送流中的传输顺序。

Let the session information context contain additional variables:

让会话信息上下文包含其他变量:

o NEXT_TSN: the next TSN to record with a fragment's queue entry when it is transmitted, initially 1;

o NEXT_TSN:当片段被传输时,要使用其队列条目记录的下一个TSN,最初为1;

o MAX_TSN_ACK: the highest acknowledged TSN, initially 0.

o MAX_TSN_ACK:最高已确认TSN,最初为0。

Let each fragment queue entry contain an additional variable TSN, initially 0, to track its transmission order.

让每个片段队列条目包含一个附加变量TSN(最初为0),以跟踪其传输顺序。

On transmission of a message fragment into the network, set its entry.TSN to session.NEXT_TSN, and increment session.NEXT_TSN.

将消息片段传输到网络时,将其entry.TSN设置为session.NEXT_TSN,并将session.NEXT_TSN设置为increment。

On acknowledgement of an outstanding fragment, if its entry.TSN is greater than session.MAX_TSN_ACK, set session.MAX_TSN_ACK to entry.TSN.

在确认未完成的片段时,如果其entry.TSN大于session.MAX_TSN_ACK,则将session.MAX_TSN_ACK设置为entry.TSN。

After processing all acknowledgements in a packet containing at least one acknowledgement, then for each sending flow in that session, for each entry in that flow's SEND_QUEUE, if entry.IN_FLIGHT is true and

在处理包含至少一个确认的数据包中的所有确认之后,对于该会话中的每个发送流,对于该流的发送队列中的每个条目,如果entry.in_FLIGHT为true,并且

entry.TSN is less than session.MAX_TSN_ACK, increment entry.NAK_COUNT and notify the congestion control and avoidance algorithms that a negative acknowledgement was detected in this packet.

entry.TSN小于session.MAX_TSN_ACK、increment entry.NAK_COUNT,并通知拥塞控制和避免算法在此数据包中检测到否定确认。

For each sending flow in that session, for each entry in that flow's SEND_QUEUE, if entry.IN_FLIGHT is true and entry.NAK_COUNT is at least 3, that fragment was lost in the network and is no longer considered to be in flight. Set entry.IN_FLIGHT to false. Notify the congestion control and avoidance algorithms of the loss.

对于该会话中的每个发送流,对于该流的发送队列中的每个条目,如果entry.in_FLIGHT为true且entry.NAK_COUNT至少为3,则该片段在网络中丢失,不再被视为在飞行中。将entry.IN_FLIGHT设置为false。通知拥塞控制和避免算法丢失。

3.6.2.6. Timeout
3.6.2.6. 超时

A fragment is considered lost and no longer in flight in the network if it has remained outstanding for at least ERTO.

如果碎片至少在ERTO中未被清除,则认为该碎片已丢失且不再在网络中飞行。

The following describes an OPTIONAL method to manage transmission timeouts. This method REQUIRES that either burst avoidance (Section 3.5.2.3) is implemented or the implementation's congestion control and avoidance algorithms will eventually stop sending new fragments into the network if acknowledgements are persistently not received.

以下描述了管理传输超时的可选方法。该方法要求要么实施突发避免(第3.5.2.3节),要么实施的拥塞控制和避免算法最终将停止向网络发送新片段(如果持续未收到确认)。

Let the session information context contain an alarm TIMEOUT_ALARM, initially unset.

让会话信息上下文包含警报超时\警报,初始未设置。

On sending a packet containing at least one User Data chunk, set or reset TIMEOUT_ALARM to fire in ERTO.

在发送包含至少一个用户数据块的数据包时,设置或重置超时报警以在ERTO中触发。

On receiving a packet containing at least one acknowledgement, reset TIMEOUT_ALARM (if already set) to fire in ERTO.

在接收到包含至少一个确认的数据包时,将超时报警(如果已设置)重置为ERTO中触发。

When TIMEOUT_ALARM fires:

当超时报警触发时:

1. Set WAS_LOSS = false;

1. 设置为_LOSS=false;

2. For each sending flow in the session, and for each entry in that flow's SEND_QUEUE:

2. 对于会话中的每个发送流以及该流的发送队列中的每个条目:

1. If entry.IN_FLIGHT is true, set WAS_LOSS = true; and

1. 如果entry.IN_FLIGHT为true,则set WAS_LOSS=true;和

2. Set entry.IN_FLIGHT to false.

2. 将entry.IN_FLIGHT设置为false。

3. If WAS_LOSS is true, perform ERTO backoff (Section 3.5.2.2); and

3. 如果WAS_损失为真,则执行ERTO回退(第3.5.2.2节);和

4. Notify the congestion control and avoidance algorithms of the timeout and, if WAS_LOSS is true, that there was loss.

4. 将超时通知拥塞控制和避免算法,如果WAS_丢失为真,则通知丢失。

3.6.2.7. Abandoning Data
3.6.2.7. 放弃数据

The application can abandon queued messages at any time and for any reason. Example reasons include (but are not limited to) the following: one or more fragments of a message have remained in the SEND_QUEUE for longer than a specified message lifetime; a fragment has been retransmitted more than a specified retransmission limit; a prior message on which this message depends (such as a key frame in a prediction chain) was abandoned and not delivered.

应用程序可以随时出于任何原因放弃排队的消息。示例原因包括(但不限于):消息的一个或多个片段在发送队列中的保留时间超过了指定的消息生存期;片段已被重传超过指定的重传限制;此消息所依赖的先前消息(如预测链中的关键帧)已被放弃且未交付。

To abandon a message fragment, set its SEND_QUEUE entry's ABANDON flag to true. When abandoning a message fragment, abandon all fragments of the message to which it belongs.

要放弃消息片段,请将其发送队列条目的放弃标志设置为true。放弃消息片段时,放弃它所属的所有消息片段。

An abandoned fragment MUST NOT be un-abandoned.

被遗弃的碎片不能被取消遗弃。

3.6.2.7.1. Forward Sequence Number Update
3.6.2.7.1. 正向序列号更新

Abandoned data may leave gaps in the sequence number space of a flow. Gaps may cause the receiver to hold completely received messages for ordered delivery to allow for retransmission of the missing fragments. User Data chunks (Section 2.3.11) encode a Forward Sequence Number (FSN) to instruct the receiver that fragments with sequence numbers less than or equal to the FSN will not be transmitted or retransmitted.

废弃的数据可能会在流的序列号空间中留下间隙。间隙可能导致接收器保留完全接收到的消息以进行有序传递,从而允许重新传输丢失的片段。用户数据块(第2.3.11节)对前向序列号(FSN)进行编码,以指示接收器序列号小于或等于FSN的片段将不会被传输或重新传输。

When the receiver has gaps in the received sequence number space and no non-abandoned message fragments remain in the SEND_QUEUE, the sender SHOULD transmit a Forward Sequence Number Update (FSN Update) comprising a User Data chunk marked abandoned, whose sequence number is the FSN and whose fsnOffset is 0. An FSN Update allows the receiver to skip gaps that will not be repaired and deliver received messages to the user. An FSN Update may be thought of as a transmission or retransmission of abandoned sequence numbers without actually sending the data.

当接收方在接收到的序列号空间中有间隙且发送队列中没有未放弃的消息片段时,发送方应发送一个前向序列号更新(FSN更新),该前向序列号更新包含一个标记为放弃的用户数据块,其序列号为FSN,其fsnOffset为0。FSN更新允许接收方跳过无法修复的间隙,并将接收到的消息传递给用户。FSN更新可以被认为是在不实际发送数据的情况下传输或重新传输放弃的序列号。

The method described in Section 3.6.2.3 ("Sending Data") generates FSN Updates when appropriate.

第3.6.2.3节(“发送数据”)中描述的方法在适当时生成FSN更新。

3.6.2.8. Examples
3.6.2.8. 例子
    Sender
      |                   :
    1 |<---  Ack  ID=2, seq:0-16
    2 |--->  Data ID=2, seq#=25, fsnOff=9 (fsn=16)
    3 |--->  Data ID=2, seq#=26, fsnOff=10 (fsn=16)
    4 |<---  Ack  ID=2, seq:0-18
    5 |--->  Data ID=2, seq#=27, fsnOff=9 (fsn=18)
    6 |--->  Data ID=2, seq#=28, fsnOff=10 (fsn=18)
      |                   :
        
    Sender
      |                   :
    1 |<---  Ack  ID=2, seq:0-16
    2 |--->  Data ID=2, seq#=25, fsnOff=9 (fsn=16)
    3 |--->  Data ID=2, seq#=26, fsnOff=10 (fsn=16)
    4 |<---  Ack  ID=2, seq:0-18
    5 |--->  Data ID=2, seq#=27, fsnOff=9 (fsn=18)
    6 |--->  Data ID=2, seq#=28, fsnOff=10 (fsn=18)
      |                   :
        

There are 9 sequence numbers in flight with delayed acknowledgements.

航班上有9个序列号,确认延迟。

Figure 20: Normal Flow with No Loss

图20:无损失的正常流量

    Sender
      |                   :
    1 |<---  Ack  ID=3, seq:0-30
    2 |--->  Data ID=3, seq#=45, fsnOff=15 (fsn=30)
    3 |<---  Ack  ID=3, seq:0-30, 32 (nack 31:1)
    4 |--->  Data ID=3, seq#=46, fsnOff=16 (fsn=30)
    5 |<---  Ack  ID=3, seq:0-30, 32, 34 (nack 31:2, 33:1)
    6 |<---  Ack  ID=3, seq:0-30, 32, 34-35 (nack 31:3=lost, 33:2)
    7 |--->  Data ID=3, seq#=47, fsnOff=15 (fsn=32, abandon 31)
    8 |<---  Ack  ID=3, seq:0-30, 32, 34-36 (nack 33:3=lost)
    9 |--->  Data ID=3, seq#=33, fsnOff=1 (fsn=32, retransmit 33)
   10 |<---  Ack  ID=3, seq:0-30, 32, 34-37
   11 |--->  Data ID=3, seq#=48, fsnOff=16 (fsn=32)
      |                   :
      |      (continues through seq#=59)
      |                   :
   12 |--->  Data ID=3, seq#=60, fsnOff=28(fsn=32)
   13 |<---  Ack  ID=3, seq:0-30, 34-46
   14 |--->  Data ID=3, seq#=61, fsnOff=29 (fsn=32)
   15 |<---  Ack  ID=3, seq:0-32, 34-47
   16 |--->  Data ID=3, seq#=62, fsnOff=30 (fsn=32)
   17 |<---  Ack  ID=3, seq:0-47
   18 |--->  Data ID=3, seq#=63, fsnOff=16 (fsn=47)
   19 |<---  Ack  ID=3, seq:0-49
   20 |--->  Data ID=3, seq#=64, fsnOff=15 (fsn=49)
      |                   :
   21 |<---  Ack  ID=3, seq:0-59
   22 |<---  Ack  ID=3, seq:0-59, 61 (nack 60:1)
   23 |<---  Ack  ID=3, seq:0-59, 61-62 (nack 60:2)
   24 |<---  Ack  ID=3, seq:0-59, 61-63 (nack 60:3=lost)
   25 |--->  Data ID=3, ABN=1, seq#=60, fsnOff=0 (fsn=60, abandon 60)
   26 |<---  Ack  ID=3, seq:0-59, 61-64
      |                   :
   27 |<---  Ack  ID=3, seq:0-64
        
    Sender
      |                   :
    1 |<---  Ack  ID=3, seq:0-30
    2 |--->  Data ID=3, seq#=45, fsnOff=15 (fsn=30)
    3 |<---  Ack  ID=3, seq:0-30, 32 (nack 31:1)
    4 |--->  Data ID=3, seq#=46, fsnOff=16 (fsn=30)
    5 |<---  Ack  ID=3, seq:0-30, 32, 34 (nack 31:2, 33:1)
    6 |<---  Ack  ID=3, seq:0-30, 32, 34-35 (nack 31:3=lost, 33:2)
    7 |--->  Data ID=3, seq#=47, fsnOff=15 (fsn=32, abandon 31)
    8 |<---  Ack  ID=3, seq:0-30, 32, 34-36 (nack 33:3=lost)
    9 |--->  Data ID=3, seq#=33, fsnOff=1 (fsn=32, retransmit 33)
   10 |<---  Ack  ID=3, seq:0-30, 32, 34-37
   11 |--->  Data ID=3, seq#=48, fsnOff=16 (fsn=32)
      |                   :
      |      (continues through seq#=59)
      |                   :
   12 |--->  Data ID=3, seq#=60, fsnOff=28(fsn=32)
   13 |<---  Ack  ID=3, seq:0-30, 34-46
   14 |--->  Data ID=3, seq#=61, fsnOff=29 (fsn=32)
   15 |<---  Ack  ID=3, seq:0-32, 34-47
   16 |--->  Data ID=3, seq#=62, fsnOff=30 (fsn=32)
   17 |<---  Ack  ID=3, seq:0-47
   18 |--->  Data ID=3, seq#=63, fsnOff=16 (fsn=47)
   19 |<---  Ack  ID=3, seq:0-49
   20 |--->  Data ID=3, seq#=64, fsnOff=15 (fsn=49)
      |                   :
   21 |<---  Ack  ID=3, seq:0-59
   22 |<---  Ack  ID=3, seq:0-59, 61 (nack 60:1)
   23 |<---  Ack  ID=3, seq:0-59, 61-62 (nack 60:2)
   24 |<---  Ack  ID=3, seq:0-59, 61-63 (nack 60:3=lost)
   25 |--->  Data ID=3, ABN=1, seq#=60, fsnOff=0 (fsn=60, abandon 60)
   26 |<---  Ack  ID=3, seq:0-59, 61-64
      |                   :
   27 |<---  Ack  ID=3, seq:0-64
        

Flow with sequence numbers 31, 33, and 60 lost in transit, and a pause at 64. 33 is retransmitted; 31 and 60 are abandoned. Note that line 25 is a Forward Sequence Number Update (Section 3.6.2.7.1).

序列号为31、33和60的流在传输过程中丢失,并在64处暂停。33被重新传输;31和60被放弃。注意,第25行是正向序列号更新(第3.6.2.7.1节)。

Figure 21: Flow with Loss

图21:有损耗的流量

3.6.2.9. Flow Control
3.6.2.9. 流量控制

The flow receiver advertises the amount of new data it's willing to accept from the flow sender with the bufferBytesAvailable derived field of an acknowledgement (Sections 2.3.13 and 2.3.14).

流接收器通过确认的bufferBytesAvailable派生字段(第2.3.13节和第2.3.14节)公布其愿意从流发送器接收的新数据量。

The flow sender MUST NOT send new data into the network if flow.F_OUTSTANDING_BYTES is greater than or equal to the most recently received buffer advertisement, unless flow.EXCEPTION is true (Section 3.6.2.3).

如果flow.F_未决_字节大于或等于最近接收到的缓冲区播发,则流发送方不得向网络发送新数据,除非flow.EXCEPTION为真(第3.6.2.3节)。

3.6.2.9.1. Buffer Probe
3.6.2.9.1. 缓冲探头

The flow sender is suspended if the most recently received buffer advertisement is zero and the flow hasn't been rejected by the receiver -- that is, while RX_BUFFER_SIZE is zero AND EXCEPTION is false. To guard against potentially lost acknowledgements that might reopen the receive window, a suspended flow sender SHOULD send a packet comprising a Buffer Probe chunk (Section 2.3.15) for this flow from time to time.

如果最近接收到的缓冲区播发为零,并且流未被接收方拒绝,则流发送器将挂起——也就是说,当RX_buffer_SIZE为零且EXCEPTION为false时。为了防止可能重新打开接收窗口的潜在确认丢失,挂起的流发送方应不时为此流发送包含缓冲区探测块(第2.3.15节)的数据包。

If the receive window advertisement transitions from non-zero to zero, the flow sender MAY send a Buffer Probe immediately and SHOULD send a probe within one second.

如果接收窗口播发从非零变为零,则流发送器可立即发送缓冲区探测,并应在1秒内发送探测。

The initial period between Buffer Probes SHOULD be at least one second or ERTO, whichever is greater. The period between probes SHOULD increase over time, but the period between probes SHOULD NOT be more than one minute or ERTO, whichever is greater.

缓冲区探测之间的初始周期应至少为1秒或ERTO,以较大者为准。探头之间的周期应随时间增加,但探头之间的周期不应超过1分钟或ERTO,以较大者为准。

The flow sender SHOULD stop sending Buffer Probes if it is no longer suspended.

如果不再挂起,流发送器应停止发送缓冲区探测。

3.6.2.10. Exception
3.6.2.10. 例外

The flow receiver can reject the flow at any time and for any reason. The flow receiver sends a Flow Exception Report (Section 2.3.16) when it has rejected a flow.

流量接收器可以在任何时候出于任何原因拒绝流量。流量接收器在拒绝流量时发送流量异常报告(第2.3.16节)。

On receiving a Flow Exception Report for a sending flow:

收到发送流的流异常报告时:

1. If the flow is F_OPEN, close the flow (Section 3.6.2.11) and notify the user that the far end reported an exception with the encoded exception code;

1. 如果流量为F_打开,则关闭流量(第3.6.2.11节),并通知用户远端报告了带有编码异常代码的异常;

2. Set the EXCEPTION flag to true; and

2. 将异常标志设置为true;和

3. For each entry in SEND_QUEUE, set entry.ABANDONED = true.

3. 对于发送队列中的每个条目,将entry.audded设置为true。

3.6.2.11. Close
3.6.2.11. 关

A sending flow is closed by the user or as a result of an exception. To close an F_OPEN flow:

发送流由用户关闭或由于异常而关闭。要关闭F_开放流,请执行以下操作:

1. Move to the F_CLOSING state;

1. 移动到F_关闭状态;

2. If the SEND_QUEUE is not empty, AND the tail entry of the SEND_QUEUE has a sequence number of NEXT_SN - 1, AND the tail entry.EVER_SENT is false, set F_FINAL_SN to entry.SEQUENCE_NUMBER; else

2. 如果发送队列不为空,且发送队列的尾部条目的序号为NEXT\u SN-1,且尾部条目.EVER\u SENT为false,则将F\u FINAL\u SN设置为entry.sequence\u number;其他的

3. The SEND_QUEUE is empty, OR the tail entry does not have a sequence number of NEXT_SN - 1, OR the tail entry.EVER_SENT is true: enqueue a new SEND_QUEUE entry with entry.SEQUENCE_NUMBER = flow.NEXT_SN, entry.FRA = 0, and entry.ABANDONED = true, and set flow.F_FINAL_SN to entry.SEQUENCE_NUMBER.

3. 发送队列为空,或者尾部条目没有NEXT\u SN-1的序列号,或者尾部条目。EVERT\u SENT为true:将一个新的发送队列条目加入到entry.sequence\u number=flow.NEXT\u SN、entry.FRA=0和entry.FACTURED=true的队列中,并将flow.F\u FINAL\u SN设置为entry.sequence\u number。

An F_CLOSING sending flow is complete when its SEND_QUEUE transitions to empty, indicating that all sequence numbers, including the FINAL_SN, have been acknowledged by the other end.

当F_关闭发送流的发送队列转换为空时,F_关闭发送流即完成,这表示所有序列号(包括最终的序列号)已被另一端确认。

When an F_CLOSING sending flow becomes complete, move to the F_COMPLETE_LINGER state.

当F_关闭发送流完成时,移动到F_complete_LINGER状态。

A sending flow MUST remain in the F_COMPLETE_LINGER state for at least 130 seconds. After at least 130 seconds, move to the F_CLOSED state. The sending flow is now closed, its resources can be reclaimed, and its F_FLOW_ID MAY be used for a new sending flow.

发送流必须保持F_COMPLETE_LINGER状态至少130秒。至少130秒后,移到F_关闭状态。发送流现在已关闭,其资源可以回收,其F_flow_ID可用于新的发送流。

3.6.3. Receiver
3.6.3. 接受者

Each receiving flow comprises the flow-specific information context necessary to receive that flow's messages from the sending end and deliver completed messages to the user. Each receiving flow context includes at least:

每个接收流包括从发送端接收该流的消息并将完成的消息传递给用户所需的流特定信息上下文。每个接收流上下文至少包括:

o RF_FLOW_ID: this flow's identifier;

o RF_FLOW_ID:此流的标识符;

o SEQUENCE_SET: the set of all fragment sequence numbers seen in this receiving flow, whether received or abandoned, initially empty;

o SEQUENCE_SET:在该接收流中看到的所有片段序列号的集合,无论是接收的还是放弃的,最初为空;

o RF_FINAL_SN: the final fragment sequence number of the flow, initially having no value;

o RF_FINAL_SN:流的最终片段序列号,最初没有值;

o RECV_BUFFER: the message fragments waiting to be delivered to the user, sorted by sequence number in ascending order, initially empty; each message fragment entry comprising the following:

o RECV_BUFFER:等待发送给用户的消息片段,按序列号升序排序,初始为空;每个消息片段条目包括以下内容:

* SEQUENCE_NUMBER: the sequence number of this fragment;

* 序列号:该片段的序列号;

* DATA: this fragment's user data; and

* 数据:该片段的用户数据;和

* FRA: the fragment control value for this message fragment, having one of the values enumerated for that purpose in Section 2.3.11 ("User Data Chunk").

* FRA:此消息片段的片段控制值,具有第2.3.11节(“用户数据块”)中为此目的枚举的值之一。

o BUFFERED_SIZE: the sum of the lengths of each fragment in RECV_BUFFER plus any additional storage overhead for the fragments incurred by the implementation, in bytes;

o BUFFERED_SIZE:RECV_BUFFER中每个片段的长度加上实现产生的片段的任何额外存储开销之和,以字节为单位;

o BUFFER_CAPACITY: the desired maximum size for the receive buffer, in bytes;

o 缓冲区容量:接收缓冲区所需的最大大小,以字节为单位;

o PREV_RWND: the most recent receive window advertisement sent in an acknowledgement, in 1024-byte blocks, initially having no value;

o PREV_RWND:在确认中发送的最新接收窗口广告,以1024字节块为单位,最初没有值;

o SHOULD_ACK: whether or not an acknowledgement should be sent for this flow, initially false;

o 应确认:是否应为此流发送确认,最初为false;

o EXCEPTION_CODE: the exception code to report to the sender when the flow has been rejected, initially 0;

o 异常代码:流被拒绝时向发送方报告的异常代码,最初为0;

o The state, at any time being one of the following values: the open state RF_OPEN; the closing states RF_REJECTED and RF_COMPLETE_LINGER; and the closed state RF_CLOSED.

o 状态,在任何时候为以下值之一:打开状态RF_open;关闭状态RF_拒绝和RF_完成;关闭状态RF_关闭。

Note: The following diagram is only a summary of state transitions and their causing events, and is not a complete operational specification.

注意:下图只是状态转换及其导致事件的摘要,不是完整的操作规范。

                                       +-+
                                       |X|
                                       +-+
                                        |rcv User Data for
                                        |  no existing flow
                                        v
                                   +---------+
                                   | RF_OPEN |
                                   +---------+
              rcv all sequence numbers|   |user reject,
                      0..RF_FINAL_SN  |   |rcv bad option,
                                      |   |no metadata at open,
                                      |   |association specified
                                      |   |  but not F_OPEN at open
                                  +---+   |
                                  |       v
                                  |  +-----------+
                                  |  |RF_REJECTED|
                                  |  +-----------+
                                  |       |rcv all sequence numbers
                                  |       |  0..RF_FINAL_SN
                                  v       v
                             +------------------+
                             |RF_COMPLETE_LINGER|
                             +------------------+
                                      | 120 seconds
                                      v
                                 +---------+
                                 |RF_CLOSED|
                                 +---------+
        
                                       +-+
                                       |X|
                                       +-+
                                        |rcv User Data for
                                        |  no existing flow
                                        v
                                   +---------+
                                   | RF_OPEN |
                                   +---------+
              rcv all sequence numbers|   |user reject,
                      0..RF_FINAL_SN  |   |rcv bad option,
                                      |   |no metadata at open,
                                      |   |association specified
                                      |   |  but not F_OPEN at open
                                  +---+   |
                                  |       v
                                  |  +-----------+
                                  |  |RF_REJECTED|
                                  |  +-----------+
                                  |       |rcv all sequence numbers
                                  |       |  0..RF_FINAL_SN
                                  v       v
                             +------------------+
                             |RF_COMPLETE_LINGER|
                             +------------------+
                                      | 120 seconds
                                      v
                                 +---------+
                                 |RF_CLOSED|
                                 +---------+
        

Figure 22: Receiving Flow State Diagram

图22:接收流状态图

3.6.3.1. Startup
3.6.3.1. 启动

A new receiving flow starts on receipt of a User Data chunk (Section 2.3.11) encoding a flow ID not belonging to any other receiving flow in the same session in the RF_OPEN, RF_REJECTED, or RF_COMPLETE_LINGER states.

新的接收流在接收到用户数据块(第2.3.11节)时开始,该用户数据块编码的流ID不属于同一会话中处于RF_打开、RF_拒绝或RF_完成逗留状态的任何其他接收流。

On receipt of such a User Data chunk:

在收到此类用户数据块时:

1. Set temporary variables METADATA, ASSOCIATED_FLOWID, and ASSOCIATION to each have no value;

1. 设置临时变量元数据、关联的\u FLOWID和关联,每个变量都没有值;

2. Create a new receiving flow context in this session, setting its RF_FLOW_ID to the flow ID encoded in the opening User Data chunk, and set to the RF_OPEN state;

2. 在此会话中创建新的接收流上下文,将其RF_flow_ID设置为打开的用户数据块中编码的流ID,并设置为RF_打开状态;

3. If the opening User Data chunk encodes a User's Per-Flow Metadata option (Section 2.3.11.1.1), set METADATA to option.userMetadata;

3. 如果打开的用户数据块编码用户的每流元数据选项(第2.3.11.1.1节),则将元数据设置为option.userMetadata;

4. If the opening User Data chunk encodes a Return Flow Association option (Section 2.3.11.1.2), set ASSOCIATED_FLOWID to option.flowID;

4. 如果期初用户数据块编码返回流关联选项(第2.3.11.1.2节),则将关联的\u FLOWID设置为option.FLOWID;

5. If METADATA has no value, the receiver MUST reject the flow (Section 3.6.3.7), moving it to the RF_REJECTED state;

5. 如果元数据没有值,接收方必须拒绝流(第3.6.3.7节),将其移动到RF_拒绝状态;

6. If ASSOCIATED_FLOWID has a value, then if there is no sending flow in the same session with a flow ID of ASSOCIATED_FLOWID, the receiver MUST reject the flow, moving it to the RF_REJECTED state; otherwise, set ASSOCIATION to the indicated sending flow;

6. 如果关联的\u FLOWID有一个值,那么如果在同一会话中没有具有关联的\u FLOWID的流ID的发送流,则接收器必须拒绝该流,将其移动到RF\u拒绝状态;否则,将关联设置为指示的发送流;

7. If ASSOCIATION indicates a sending flow, AND that sending flow's state is not F_OPEN, the receiver MUST reject this receiving flow, moving it to the RF_REJECTED state;

7. 如果关联指示发送流,并且发送流的状态不是F_打开,则接收器必须拒绝该接收流,将其移动到RF_拒绝状态;

8. If the opening User Data chunk encodes any unrecognized option with a type code less than 8192 (Section 2.3.11.1), the receiver MUST reject the flow, moving it to the RF_REJECTED state;

8. 如果打开的用户数据块编码任何类型代码小于8192的未识别选项(第2.3.11.1节),接收器必须拒绝该流,将其移动到RF_拒绝状态;

9. If this new receiving flow is still RF_OPEN, then notify the user that a new receiving flow has opened, including the METADATA and, if present, the ASSOCIATION, and set flow.BUFFER_CAPACITY according to the user;

9. 如果此新接收流仍处于RF_打开状态,则通知用户新接收流已打开,包括元数据和关联(如果存在),并根据用户设置flow.BUFFER_容量;

10. Perform the normal data processing (Section 3.6.3.2) for the opening User Data chunk; and

10. 对期初用户数据块进行正常数据处理(第3.6.3.2节);和

11. Set this session's ACK_NOW to true.

11. 现在将此会话的确认设置为true。

3.6.3.2. Receiving Data
3.6.3.2. 接收数据

A User Data chunk (Section 2.3.11) or a Next User Data chunk (Section 2.3.12) encodes one fragment of a user data message of a flow, as well as the flow's Forward Sequence Number and potentially optional parameters (Section 2.3.11.1).

用户数据块(第2.3.11节)或下一个用户数据块(第2.3.12节)编码流的用户数据消息的一个片段,以及流的前向序列号和可能的可选参数(第2.3.11.1节)。

On receipt of a User Data or Next User Data chunk:

收到用户数据或下一个用户数据块时:

1. If chunk.flowID doesn't indicate an existing receiving flow in the same session in the RF_OPEN, RF_REJECTED, or RF_COMPLETE_LINGER state, perform the steps of Section 3.6.3.1 ("Startup") to start a new receiving flow;

1. 如果chunk.flowID在RF_OPEN、RF_REJECTED或RF_COMPLETE_LINGER状态下未指示同一会话中的现有接收流,则执行第3.6.3.1节(“启动”)中的步骤以启动新的接收流;

2. Retrieve the receiving flow context for the flow indicated by chunk.flowID;

2. 检索chunk.flowID指示的流的接收流上下文;

3. Set flow.SHOULD_ACK to true;

3. 将flow.SHOULD_ACK设置为true;

4. If the flow is RF_OPEN, AND the chunk encodes any unrecognized option with a type code less than 8192 (Section 2.3.11.1), the flow MUST be rejected: notify the user of an exception, and reject the flow (Section 3.6.3.7), moving it to the RF_REJECTED state;

4. 如果流为RF_OPEN,且区块编码任何类型代码小于8192的未识别选项(第2.3.11.1节),则必须拒绝流:通知用户异常,并拒绝流(第3.6.3.7节),将其移动到RF_拒绝状态;

5. If the flow is not in the RF_OPEN state, set session.ACK_NOW to true;

5. 如果流未处于RF_打开状态,请立即将session.ACK_设置为true;

6. If flow.PREV_RWND has a value and that value is less than 2 blocks, set session.ACK_NOW to true;

6. 如果flow.PREV_RWND有一个值且该值小于2个块,则立即将session.ACK_设置为true;

7. If chunk.abandon is true, set session.ACK_NOW to true;

7. 如果chunk.adward为true,则立即将session.ACK_设置为true;

8. If flow.SEQUENCE_SET has any gaps (that is, if it doesn't contain every sequence number from 0 through and including the highest sequence number in the set), set session.ACK_NOW to true;

8. 如果flow.SEQUENCE_集合有任何间隙(即,如果它不包含从0到的所有序列号,并且不包含集合中的最高序列号),请立即将session.ACK_设置为true;

9. If flow.SEQUENCE_SET contains chunk.sequenceNumber, then this chunk is a duplicate: set session.ACK_NOW to true;

9. 如果flow.SEQUENCE\u集包含chunk.sequenceNumber,则此chunk是重复的:立即将session.ACK\u设置为true;

10. If flow.SEQUENCE_SET doesn't contain chunk.sequenceNumber, AND chunk.final is true, AND flow.RF_FINAL_SN has no value, then set flow.RF_FINAL_SN to chunk.sequenceNumber, and set session.ACK_NOW to true;

10. 如果flow.SEQUENCE\u SET不包含chunk.sequenceNumber,且chunk.final为true,且flow.RF\u final\u SN没有值,则将flow.RF\u final\u SN设置为chunk.sequenceNumber,并立即将session.ACK\u设置为true;

11. If the flow is in the RF_OPEN state, AND flow.SEQUENCE_SET doesn't contain chunk.sequenceNumber, AND chunk.abandon is false, then create a new RECV_BUFFER entry for this chunk's data and set entry.SEQUENCE_NUMBER to chunk.sequenceNumber, entry.DATA to chunk.userData, and entry.FRA to chunk.fragmentControl, and insert this new entry into flow.RECV_BUFFER;

11. 如果流处于RF_打开状态,且flow.SEQUENCE_集合不包含chunk.sequenceNumber,且chunk.About为false,则为该区块的数据创建新的RECV_缓冲区条目,并将entry.SEQUENCE_NUMBER设置为chunk.sequenceNumber,entry.data设置为chunk.userData,entry.FRA设置为chunk.fragmentControl,并将此新条目插入flow.RECV_BUFFER;

12. Add to flow.SEQUENCE_SET the range of sequence numbers from 0 through and including the chunk.forwardSequenceNumber derived field;

12. 添加到flow.SEQUENCE\设置从0到包括chunk.forwardSequenceNumber派生字段的序列号范围;

13. Add chunk.sequenceNumber to flow.SEQUENCE_SET;

13. 将chunk.sequenceNumber添加到flow.SEQUENCE\u集合;

14. If flow.SEQUENCE_SET now has any gaps, set session.ACK_NOW to true;

14. 如果flow.SEQUENCE\u SET现在有任何间隙,请将session.ACK\u now设置为true;

15. If session.ACK_NOW is false and session.DELACK_ALARM is not set, set session.DELACK_ALARM to fire in 200 milliseconds; and

15. 如果session.ACK\u NOW为false且未设置session.DELACK\u报警,请将session.DELACK\u报警设置为在200毫秒内触发;和

16. Attempt delivery of completed messages in this flow's RECV_BUFFER to the user (Section 3.6.3.3).

16. 尝试将此流的RECV_缓冲区中已完成的消息传递给用户(第3.6.3.3节)。

After processing all chunks in a packet containing at least one User Data chunk, increment session.RX_DATA_PACKETS by one. If session.RX_DATA_PACKETS is at least two, set session.ACK_NOW to true.

在处理包含至少一个用户数据块的数据包中的所有数据块后,将session.RX_Data_数据包增加一个。如果session.RX_DATA_数据包至少有两个,请立即将session.ACK_设置为true。

A receiving flow that is not in the RF_CLOSED state is ready to send an acknowledgement if its SHOULD_ACK flag is set. Acknowledgements for receiving flows that are ready are sent either opportunistically by piggybacking on a packet that's already sending user data or an acknowledgement (Section 3.6.3.4.6), or when the session's ACK_NOW flag is set (Section 3.6.3.4.5).

如果设置了应确认标志,则不处于RF_关闭状态的接收流准备发送确认。通过在已经发送用户数据的数据包或确认(第3.6.3.4.6节),或者在设置会话的ACK_NOW标志(第3.6.3.4.5节)的情况下,机会主义地发送接收流的确认(第3.6.3.4.6节)。

3.6.3.3. Buffering and Delivering Data
3.6.3.3. 缓冲和传递数据

A receiving flow's information context contains a RECV_BUFFER for reordering, reassembling, and holding the user data messages of the flow. Only complete messages are delivered to the user; an implementation MUST NOT deliver partially received messages, except by special arrangement with the user.

接收流的信息上下文包含一个RECV_缓冲区,用于重新排序、重新组合和保存流的用户数据消息。只向用户发送完整的消息;除非通过与用户的特殊安排,否则实现不得传递部分接收的消息。

Let the Cumulative Acknowledgement Sequence Number (CSN) be the highest number in the contiguous range of numbers in SEQUENCE_SET starting with 0. For example, if SEQUENCE_SET contains {0, 1, 2, 3, 5, 6}, the contiguous range starting with 0 is 0..3, so the CSN is 3.

让累积确认序列号(CSN)为序列_集合中从0开始的连续数字范围中的最高数字。例如,如果序列_集包含{0,1,2,3,5,6},则从0开始的连续范围是0..3,因此CSN是3。

A message is complete if all of its fragments are present in the RECV_BUFFER. The fragments of one message have contiguous sequence numbers. A message can be either a single fragment, whose fragment control value is 0-whole, or two or more fragments where the first's fragment control value is 1-begin, followed by zero or more fragments with control value 3-middle, and terminated by a last fragment with control value 2-end.

如果RECV_缓冲区中存在消息的所有片段,则消息已完成。一条消息的片段具有连续的序列号。消息可以是单个片段(其片段控制值为0-整数),也可以是两个或多个片段,其中第一个片段控制值为1-begin,后面是零个或多个控制值为3-MIDLE的片段,最后一个控制值为2-end的片段终止。

An incomplete message segment is a contiguous sequence of one or more fragments that do not form a complete message -- that is, a 1-begin followed by zero or more 3-middle fragments but with no 2-end, or zero or more 3-middle fragments followed by a 2-end but with no 1-begin, or one or more 3-middle fragments with neither a 1-begin nor a 2-end.

不完整的消息段是由一个或多个不构成完整消息的片段组成的连续序列,即,一个1-begin后跟零个或多个3-middle片段但没有2-end,或者零个或多个3-middle片段后跟一个2-end但没有1-begin,或者一个或多个3-middle片段既没有1-begin也没有2-end。

Incomplete message segments can either be in progress or abandoned. An incomplete segment is abandoned in the following cases:

不完整的消息段可能正在进行中,也可能被放弃。在以下情况下,将放弃不完整的段:

o The sequence number of the segment's first fragment is less than or equal to the CSN, AND that fragment's control value is not 1-begin; or

o 片段的第一个片段的序列号小于或等于CSN,并且该片段的控制值不是1-begin;或

o The sequence number of the segment's last fragment is less than the CSN.

o 片段最后一个片段的序列号小于CSN。

Abandoned message segments will never be completed, so they SHOULD be removed from the RECV_BUFFER to make room in the advertised receive window and the receiver's memory for messages that can be completed.

废弃的消息段永远不会完成,因此应将其从RECV_缓冲区中删除,以便在播发的接收窗口和接收者的内存中腾出空间来存储可以完成的消息。

The user can suspend delivery of a flow's messages. A suspended receiving flow holds completed messages in its RECV_BUFFER until the user resumes delivery. A suspended flow can cause the receive window advertisement to go to zero even when the BUFFER_CAPACITY is non-zero; this is described in detail in Section 3.6.3.5 ("Flow Control").

用户可以暂停流消息的传递。挂起的接收流将完成的消息保存在其RECV_缓冲区中,直到用户恢复传递。即使在缓冲区容量非零时,暂停的流也会导致接收窗口广告变为零;第3.6.3.5节(“流量控制”)对此进行了详细说明。

When the receiving flow is not suspended, the original queuing order of the messages is recovered by delivering, in ascending sequence number order, complete messages in the RECV_BUFFER whose sequence numbers are less than or equal to the CSN.

当接收流未挂起时,通过以升序顺序在RECV_缓冲区中发送序列号小于或等于CSN的完整消息,恢复消息的原始排队顺序。

The following describes a method for discarding abandoned message segments and delivering complete messages in original queuing order when the receiving flow is not suspended.

下面描述了在接收流未挂起时丢弃废弃的消息段并按原始队列顺序传递完整消息的方法。

While the first fragment entry in the RECV_BUFFER has a sequence number less than or equal to the CSN and delivery is still possible:

尽管RECV_缓冲区中的第一个片段条目的序列号小于或等于CSN,但仍然可以传递:

1. If entry.FRA is 0-whole, deliver entry.DATA to the user, and remove this entry from RECV_BUFFER; otherwise,

1. 如果entry.FRA为0-full,则将entry.DATA传递给用户,并将该条目从RECV_缓冲区中删除;否则

2. If entry.FRA is 2-end or 3-middle, this entry belongs to an abandoned segment, so remove and discard this entry from RECV_BUFFER; otherwise,

2. 如果entry.FRA为2-end或3-middle,则该条目属于废弃段,因此从RECV_缓冲区中删除并丢弃该条目;否则

3. Entry.FRA is 1-begin. Let LAST_ENTRY be the last RECV_BUFFER entry that is part of this message segment (LAST_ENTRY can be entry if the segment has only one fragment so far). Then:

3. Entry.FRA是1-begin。设LAST_条目为属于此消息段的最后一个RECV_缓冲区条目(如果该段到目前为止只有一个片段,则LAST_条目可以为条目)。然后:

1. If LAST_ENTRY.FRA is 2-end, this segment is a complete message, so concatenate the DATA fields of each fragment entry of this segment in ascending sequence number order and deliver the complete message to the user, then remove the entries for this complete message from RECV_BUFFER; otherwise,

1. 如果LAST_ENTRY.FRA为2-end,则该段为完整消息,因此以升序顺序连接该段的每个片段条目的数据字段,并将完整消息传递给用户,然后从RECV_缓冲区中删除该完整消息的条目;否则

2. If LAST_ENTRY.SEQUENCE_NUMBER is less than CSN, this segment is incomplete and abandoned, so remove and discard the entries for this segment from RECV_BUFFER; otherwise,

2. 如果LAST_ENTRY.SEQUENCE_NUMBER小于CSN,则此段不完整且已放弃,因此从RECV_缓冲区中删除并放弃此段的条目;否则

3. LAST_ENTRY.SEQUENCE_NUMBER is equal to CSN and LAST_ENTRY.FRA is not 2-end: this segment is incomplete but still in progress. Ordered delivery is no longer possible until at least one more fragment is received. Stop.

3. LAST_ENTRY.SEQUENCE_编号等于CSN,LAST_ENTRY.FRA不是2端:此段不完整,但仍在进行中。在至少收到一个或多个碎片之前,无法再进行有序交付。停止

If flow.RF_FINAL_SN has a value and is equal to the CSN, AND RECV_BUFFER is empty, all complete messages have been delivered to the user, so notify the user that the flow is complete.

如果flow.RF_FINAL_SN有一个值并且等于CSN,并且RECV_BUFFER为空,则所有完整的消息都已传递给用户,因此通知用户流已完成。

3.6.3.4. Acknowledging Data
3.6.3.4. 确认数据

A flow receiver SHOULD acknowledge all user data fragment sequence numbers seen in that flow. Acknowledgements drive the sender's congestion control and avoidance algorithms, clear data from the sender's buffers, and in some sender implementations clock new data into the network; therefore, the acknowledgements must be accurate and timely.

流接收器应该确认在该流中看到的所有用户数据片段序列号。确认驱动发送方的拥塞控制和避免算法,清除发送方缓冲区中的数据,在某些发送方实现中,将新数据时钟输入网络;因此,确认必须准确及时。

3.6.3.4.1. Timing
3.6.3.4.1. 时机

For reasons similar to those discussed in Section 4.2.3.2 of RFC 1122 [RFC1122], it is advantageous to delay sending acknowledgements for a short time, so that multiple data fragments can be acknowledged in a single transmission. However, it is also advantageous for a sender to receive timely notification about the receiver's disposition of the flow, particularly in unusual or exceptional circumstances, so that the circumstances can be addressed if possible.

出于与RFC 1122[RFC1122]第4.2.3.2节中讨论的原因类似的原因,有利于短时间延迟发送确认,以便在一次传输中确认多个数据片段。然而,对于发送方来说,及时接收关于接收方对流的处理的通知也是有利的,特别是在异常或例外情况下,以便在可能的情况下可以处理这些情况。

Therefore, a flow receiver SHOULD send an acknowledgement for a flow as soon as is practical in any of the following circumstances:

因此,在以下任何情况下,流接收器应尽快发送流确认:

o On receipt of a User Data chunk that starts a new flow;

o 在接收到启动新流的用户数据块时;

o On receipt of a User Data or Next User Data chunk if the flow is not in the RF_OPEN state;

o 在收到用户数据或下一个用户数据块时(如果流未处于RF_打开状态);

o On receipt of a User Data chunk where, before processing the chunk, the SEQUENCE_SET of the indicated flow does not contain every sequence number between 0 and the highest sequence number in the set (that is, if there was a sequence number gap before processing the chunk);

o 在接收到用户数据块时,其中,在处理该块之前,指示流的序列集不包含0和该集中最高序列号之间的每个序列号(即,如果在处理该块之前存在序列号间隙);

o On receipt of a User Data chunk where, after processing the chunk, the flow's SEQUENCE_SET does not contain every sequence number between 0 and the highest sequence number in the set (that is, if this chunk causes a sequence number gap);

o 在接收到用户数据块时,其中在处理该块之后,流的序列_集合不包含集合中0和最高序列号之间的每个序列号(即,如果该块导致序列号间隙);

o On receipt of a Buffer Probe for the flow;

o 收到流量缓冲探头后;

o On receipt of a User Data chunk if the last acknowledgement sent for the flow indicated fewer than two bufferBlocksAvailable;

o 在收到用户数据块时,如果为流发送的最后确认指示少于两个bufferBlocksAvailable;

o On receipt of a User Data or Next User Data chunk for the flow if, after processing the chunk, the flow's BUFFER_CAPACITY is not at least 1024 bytes greater than BUFFERED_SIZE;

o 在接收到流的用户数据或下一个用户数据块时,如果在处理该块之后,流的缓冲区_容量不大于缓冲区_大小至少1024字节;

o On receipt of a User Data or Next User Data chunk for any sequence number that was already seen (that is, on receipt of a duplicate);

o 在接收到已看到的任何序列号的用户数据或下一个用户数据块时(即,在接收到副本时);

o On the first receipt of the final sequence number of the flow;

o 在第一次收到流的最终序列号时;

o On receipt of two packets in the session that contain user data for any flows since an acknowledgement was last sent, the new acknowledgements being for the flows having any User Data chunks in the received packets (that is, for every second packet containing user data);

o 在会话中接收到包含自上次发送确认以来的任何流的用户数据的两个分组时,新的确认用于在接收到的分组中具有任何用户数据块的流(即,对于包含用户数据的每第二个分组);

o After receipt of a User Data chunk for the flow, if an acknowledgement for any other flow is being sent (that is, consolidate acknowledgements);

o 在收到流的用户数据块之后,如果正在发送任何其他流的确认(即,合并确认);

o After receipt of a User Data chunk for the flow, if any user data for a sending flow is being sent in a packet and if there is space available in the same packet (that is, attempt to piggyback an acknowledgement with user data if possible);

o 在接收到流的用户数据块之后,如果发送流的任何用户数据正在分组中发送,并且同一分组中是否有可用空间(即,如果可能,尝试使用用户数据背载确认);

o No longer than 200 milliseconds after receipt of a User Data chunk for the flow.

o 在收到流的用户数据块后不超过200毫秒。

3.6.3.4.2. Size and Truncation
3.6.3.4.2. 大小和截断

Including an encoded acknowledgement in a packet might cause the packet to exceed the path MTU. In that case:

在数据包中包含编码确认可能导致数据包超出路径MTU。在这种情况下:

o If the packet is being sent primarily to send an acknowledgement, AND this is the first acknowledgement in the packet, truncate the acknowledgement so that the packet does not exceed the path MTU; otherwise,

o 如果发送分组主要是为了发送确认,并且这是分组中的第一个确认,则截断确认,使得分组不超过路径MTU;否则

o The acknowledgement is being piggybacked in a packet with user data or with an acknowledgement for another flow: do not include this acknowledgement in the packet, and send it later.

o 确认信息与用户数据或另一个流的确认信息一起装载在数据包中:不要将此确认信息包含在数据包中,稍后再发送。

3.6.3.4.3. Constructing
3.6.3.4.3. 建造

The Data Acknowledgement Bitmap chunk (Section 2.3.13) and Data Acknowledgement Ranges chunk (Section 2.3.14) encode a receiving flow's SEQUENCE_SET and its receive window advertisement. The two chunks are semantically equivalent; implementations SHOULD send whichever provides the most compact encoding of the SEQUENCE_SET.

数据确认位图块(第2.3.13节)和数据确认范围块(第2.3.14节)对接收流的序列集及其接收窗口广告进行编码。这两个语块在语义上是等价的;实现应该发送序列集合中最紧凑的编码。

When assembling an acknowledgement for a receiving flow:

组装接收流的确认时:

1. If the flow's state is RF_REJECTED, first assemble a Flow Exception Report chunk (Section 2.3.16) for flow.flowID;

1. 如果流的状态为RF_REJECTED,则首先为flow.flowID组装一个流异常报告块(第2.3.16节);

2. Choose the acknowledgement chunk type that most compactly encodes flow.SEQUENCE_SET;

2. 选择对flow.SEQUENCE\u集进行最紧凑编码的确认块类型;

3. Use the method described in Section 3.6.3.5 ("Flow Control") to determine the value for the acknowledgement chunk's bufferBlocksAvailable field.

3. 使用第3.6.3.5节(“流量控制”)中描述的方法确定确认区块的bufferBlocksAvailable字段的值。

3.6.3.4.4. Delayed Acknowledgement
3.6.3.4.4. 延迟确认

As discussed in Section 3.6.3.4.1 ("Timing"), a flow receiver can delay sending an acknowledgement for up to 200 milliseconds after receiving user data. The method described in Section 3.6.3.2 ("Receiving Data") sets the session's DELACK_ALARM.

如第3.6.3.4.1节(“定时”)所述,流量接收器可在接收到用户数据后延迟发送确认长达200毫秒。第3.6.3.2节(“接收数据”)中描述的方法设置会话的DELACK_报警。

When DELACK_ALARM fires, set ACK_NOW to true.

当DELACK_报警触发时,立即将ACK_设置为true。

3.6.3.4.5. Obligatory Acknowledgement
3.6.3.4.5. 强制承认

One or more acknowledgements should be sent as soon as is practical when the session's ACK_NOW flag is set. While the ACK_NOW flag is set:

设置会话的ACK_NOW标志后,应尽快发送一个或多个确认。设置ACK_NOW标志时:

1. Choose a receiving flow that is ready to send an acknowledgement;

1. 选择准备发送确认的接收流;

2. If there is no such flow, there is no work to do, set ACK_NOW to false, set RX_DATA_PACKETS to 0, clear the DELACK_ALARM, and stop; otherwise,

2. 如果没有这样的流,则没有工作要做,将ACK_NOW设置为false,将RX_DATA_PACKETS设置为0,清除DELACK_警报,然后停止;否则

3. Start a new packet;

3. 开始一个新的包;

4. Assemble an acknowledgement for the flow and include it in the packet, truncating it if necessary so that the packet doesn't exceed the path MTU;

4. 组装流的确认,并将其包含在数据包中,必要时将其截断,以使数据包不超过路径MTU;

5. Set flow.SHOULD_ACK to false;

5. 将flow.SHOULD_ACK设置为false;

6. Set flow.PREV_RWND to the bufferBlocksAvailable field of the included acknowledgement chunk;

6. 将flow.PREV_RWND设置为包含的确认区块的bufferBlocksAvailable字段;

7. Attempt to piggyback acknowledgements for any other flows that are ready to send an acknowledgement into the packet, as described below; and

7. 如下文所述,尝试对准备向数据包发送确认的任何其他流进行确认;和

8. Send the packet.

8. 把包裹寄出去。

3.6.3.4.6. Opportunistic Acknowledgement
3.6.3.4.6. 机会主义承认

When sending a packet with user data or an acknowledgement, any other receiving flows that are ready to send an acknowledgement should include their acknowledgements in the packet if possible.

当发送包含用户数据或确认的数据包时,准备发送确认的任何其他接收流应尽可能在数据包中包含其确认。

To piggyback acknowledgements in a packet that is already being sent, where the packet contains user data or an acknowledgement, while there is at least one receiving flow that is ready to send an acknowledgement:

要在已经发送的数据包中承载确认,其中数据包包含用户数据或确认,同时至少有一个接收流准备发送确认,请执行以下操作:

1. Assemble an acknowledgement for the flow;

1. 收集对流程的确认;

2. If the acknowledgement cannot be included in the packet without exceeding the path MTU, the packet is full; stop. Otherwise,

2. 如果在不超过路径MTU的情况下不能将确认包括在分组中,则分组已满;停止否则

3. Include the acknowledgement in the packet;

3. 在包中包括确认;

4. Set flow.SHOULD_ACK to false;

4. 将flow.SHOULD_ACK设置为false;

5. Set flow.PREV_RWND to the bufferBlocksAvailable field of the included acknowledgement chunk; and

5. 将flow.PREV_RWND设置为包含的确认区块的bufferBlocksAvailable字段;和

6. If there are no longer any receiving flows in the session that are ready to send an acknowledgement, set session.ACK_NOW to false, set session.RX_DATA_PACKETS to 0, and clear session.DELACK_ALARM.

6. 如果会话中不再有任何准备发送确认的接收流,请立即将session.ACK_设置为false,将session.RX_DATA_数据包设置为0,然后清除session.DELACK_报警。

3.6.3.4.7. Example
3.6.3.4.7. 实例

Figure 23 shows an example flow with sequence numbers 31 and 33 lost in transit; 31 is abandoned, and 33 is retransmitted.

图23显示了序列号31和33在传输过程中丢失的示例流;31被放弃,33被重新传输。

   Receiver
    1 |<---  Data ID=3, seq#=29, fsnOff=11 (fsn=18)
    2 |<---  Data ID=3, seq#=30, fsnOff=12 (fsn=18)
    3 |--->  Ack  ID=3, seq:0-30
    4 |<---  Data ID=3, seq#=32, fsnOff=12 (fsn=20)
    5 |--->  Ack  ID=3, seq:0-30, 32
    6 |<---  Data ID=3, seq#=34, fsnOff=12 (fsn=22)
    7 |--->  Ack  ID=3, seq:0-30, 32, 34
      |                   :
    8 |<---  Data ID=3, seq#=46, fsnOff=16 (fsn=30)
    9 |--->  Ack  ID=3, seq:0-30, 32, 34-46
   10 |<---  Data ID=3, seq#=47, fsnOff=15 (fsn=32)
   11 |--->  Ack  ID=3, seq:0-32, 34-47
   12 |<---  Data ID=3, seq#=33, fsnOff=1 (fsn=32)
   13 |--->  Ack  ID=3, seq#=0-47
   14 |<---  Data ID=3, seq#=48, fsnOff=16 (fsn=32)
   15 |<---  Data ID=3, seq#=49, fsnOff=17 (fsn=32)
   16 |--->  Ack  ID=3, seq#=0-49
      |                   :
        
   Receiver
    1 |<---  Data ID=3, seq#=29, fsnOff=11 (fsn=18)
    2 |<---  Data ID=3, seq#=30, fsnOff=12 (fsn=18)
    3 |--->  Ack  ID=3, seq:0-30
    4 |<---  Data ID=3, seq#=32, fsnOff=12 (fsn=20)
    5 |--->  Ack  ID=3, seq:0-30, 32
    6 |<---  Data ID=3, seq#=34, fsnOff=12 (fsn=22)
    7 |--->  Ack  ID=3, seq:0-30, 32, 34
      |                   :
    8 |<---  Data ID=3, seq#=46, fsnOff=16 (fsn=30)
    9 |--->  Ack  ID=3, seq:0-30, 32, 34-46
   10 |<---  Data ID=3, seq#=47, fsnOff=15 (fsn=32)
   11 |--->  Ack  ID=3, seq:0-32, 34-47
   12 |<---  Data ID=3, seq#=33, fsnOff=1 (fsn=32)
   13 |--->  Ack  ID=3, seq#=0-47
   14 |<---  Data ID=3, seq#=48, fsnOff=16 (fsn=32)
   15 |<---  Data ID=3, seq#=49, fsnOff=17 (fsn=32)
   16 |--->  Ack  ID=3, seq#=0-49
      |                   :
        

Figure 23: Flow Example with Loss

图23:有损耗的流量示例

3.6.3.5. Flow Control
3.6.3.5. 流量控制

The flow receiver maintains a buffer for reassembling and reordering messages for delivery to the user (Section 3.6.3.3). The implementation and the user may wish to limit the amount of resources (including buffer memory) that a flow is allowed to use.

流量接收器维护一个缓冲区,用于重新组装和重新排序消息,以便交付给用户(第3.6.3.3节)。实现和用户可能希望限制允许流使用的资源量(包括缓冲存储器)。

RTMFP provides a means for each receiving flow to govern the amount of data sent by the sender, by way of the bufferBytesAvailable derived field of acknowledgement chunks (Sections 2.3.13 and 2.3.14). This derived field indicates the amount of data that the sender is allowed to have outstanding in the network, until instructed otherwise. This amount is also called the receive window.

RTMFP通过bufferBytesAvailable确认数据块派生字段(第2.3.13节和第2.3.14节),为每个接收流提供了控制发送方发送的数据量的方法。此派生字段指示允许发送方在网络中拥有未完成的数据量,除非另有指示。该金额也称为接收窗口。

The flow receiver can suspend the sender by advertising a closed (zero length) receive window.

流接收方可以通过公布一个关闭的(零长度)接收窗口来暂停发送方。

The user can suspend delivery of messages from the receiving flow (Section 3.6.3.3). This can cause the receive buffer to fill.

用户可以暂停接收流的消息传递(第3.6.3.3节)。这可能导致接收缓冲区填满。

In order for progress to be made on completing a fragmented message or repairing a gap for sequenced delivery in a flow, the flow receiver MUST advertise at least one buffer block in an acknowledgement if it is not suspended, even if the amount of data in the buffer exceeds the buffer capacity, unless the buffer capacity is 0. Otherwise, deadlock can occur, as the receive buffer will stay full and won't drain because of a gap or incomplete message, and the gap or incomplete message can't be repaired or completed because the sender is suspended.

为了在完成分段消息或修复流中顺序传递的间隙方面取得进展,流接收器必须在确认中公布至少一个缓冲块(如果未暂停),即使缓冲区中的数据量超过缓冲区容量,除非缓冲区容量为0。否则,可能会发生死锁,因为接收缓冲区将保持满,并且不会因为间隙或不完整的消息而耗尽,并且由于发送方被挂起,间隙或不完整的消息无法修复或完成。

The receive window is advertised in units of 1024-byte blocks. For example, advertisements for 1 byte, 1023 bytes, and 1024 bytes each require one block. An advertisement for 1025 bytes requires two blocks.

接收窗口以1024字节块为单位播发。例如,1字节、1023字节和1024字节的播发都需要一个块。1025字节的播发需要两个块。

The following describes the RECOMMENDED method of calculating the bufferBlocksAvailable field of an acknowledgement chunk for a receiving flow:

以下描述了计算接收流的确认块的bufferBlocksAvailable字段的推荐方法:

1. If BUFFERED_SIZE is greater than or equal to BUFFER_CAPACITY, set ADVERTISE_BYTES to 0;

1. 如果缓冲区大小大于或等于缓冲区容量,则将播发字节设置为0;

2. If BUFFERED_SIZE is less than BUFFER_CAPACITY, set ADVERTISE_BYTES to BUFFER_CAPACITY - BUFFERED_SIZE;

2. 如果缓冲区大小小于缓冲区容量,则将播发字节设置为缓冲区容量-缓冲区大小;

3. Set ADVERTISE_BLOCKS to CEIL(ADVERTISE_BYTES / 1024);

3. 将播发块设置为CEIL(播发字节/1024);

4. If ADVERTISE_BLOCKS is 0, AND BUFFER_CAPACITY is greater than 0, AND delivery to the user is not suspended, set ADVERTISE_BLOCKS to 1; and

4. 如果Advertised_BLOCKS为0,且缓冲区_容量大于0,并且向用户的传递未挂起,则将Advertised_BLOCKS设置为1;和

5. Set the acknowledgement's bufferBlocksAvailable field to ADVERTISE_BLOCKS.

5. 将确认的bufferBlocksAvailable字段设置为播发\u块。

3.6.3.6. Receiving a Buffer Probe
3.6.3.6. 接收缓冲区探测

A Buffer Probe chunk (Section 2.3.15) is sent by the flow sender (Section 3.6.2.9.1) to request the current receive window advertisement (in the form of an acknowledgement) from the flow receiver.

缓冲区探测块(第2.3.15节)由流发送方(第3.6.2.9.1节)发送,以从流接收方请求当前接收窗口广告(以确认的形式)。

On receipt of a Buffer Probe chunk:

收到缓冲区探测块时:

1. If chunk.flowID doesn't belong to a receiving flow in the same session in the RF_OPEN, RF_REJECTED, or RF_COMPLETE_LINGER state, ignore this Buffer Probe; otherwise,

1. 如果chunk.flowID不属于RF_OPEN、RF_REJECTED或RF_COMPLETE_LINGER状态下同一会话中的接收流,则忽略此缓冲区探测;否则

2. Retrieve the receiving flow context for the flow indicated by chunk.flowID; then

2. 检索chunk.flowID指示的流的接收流上下文;然后

3. Set flow.SHOULD_ACK to true; and

3. 将flow.SHOULD_ACK设置为true;和

4. Set session.ACK_NOW to true.

4. 现在将session.ACK_设置为true。

3.6.3.7. Rejecting a Flow
3.6.3.7. 拒绝流

A receiver can reject an RF_OPEN flow at any time and for any reason. To reject a receiving flow in the RF_OPEN state:

接收机可以在任何时间和任何原因拒绝射频开放流。要在RF_打开状态下拒绝接收流:

1. Move to the RF_REJECTED state;

1. 移动到RF_拒绝状态;

2. Discard all entries in flow.RECV_BUFFER, as they are no longer relevant;

2. 丢弃flow.RECV_BUFFER中的所有条目,因为它们不再相关;

3. If the user rejected the flow, set flow.EXCEPTION_CODE to the exception code indicated by the user; otherwise, the flow was rejected automatically by the implementation, so the exception code is 0;

3. 如果用户拒绝流,则将flow.EXCEPTION_CODE设置为用户指示的异常代码;否则,实现会自动拒绝该流,因此异常代码为0;

4. Set flow.SHOULD_ACK to true; and

4. 将flow.SHOULD_ACK设置为true;和

5. Set session.ACK_NOW to true.

5. 现在将session.ACK_设置为true。

The receiver indicates that it has rejected a flow by sending a Flow Exception Report chunk (Section 2.3.16) with every acknowledgement (Section 3.6.3.4.3) for a flow in the RF_REJECTED state.

接收方通过发送流异常报告区块(第2.3.16节)以及RF_拒绝状态下的流的每次确认(第3.6.3.4.3节),表明其已拒绝流。

3.6.3.8. Close
3.6.3.8. 关

A receiving flow is complete when every sequence number from 0 through and including the final sequence number has been received -- that is, when flow.RF_FINAL_SN has a value and flow.SEQUENCE_SET contains every sequence number from 0 through flow.RF_FINAL_SN, inclusive.

当接收到从0到包括最终序列号的每个序列号时,即当flow.RF_final_SN具有值且flow.sequence_SET包含从0到flow.RF_final_SN(包括)的每个序列号时,接收流完成。

When an RF_OPEN or RF_REJECTED receiving flow becomes complete, move to the RF_COMPLETE_LINGER state, set flow.SHOULD_ACK to true, and set session.ACK_NOW to true.

当RF_OPEN或RF_REJECTED接收流完成时,移动到RF_complete_LINGER状态,将flow.SHOULD_ACK设置为true,然后立即将session.ACK_设置为true。

A receiving flow SHOULD remain in the RF_COMPLETE_LINGER state for 120 seconds. After 120 seconds, move to the RF_CLOSED state. The receiving flow is now closed, and its resources can be reclaimed once all complete messages in flow.RECV_BUFFER have been delivered to the user (Section 3.6.3.3). The same flow ID might be used for a new flow by the sender after this point.

接收流应保持RF_COMPLETE_LINGER状态120秒。120秒后,移到RF_关闭状态。接收流现在已关闭,一旦flow.RECV_BUFFER中的所有完整消息交付给用户,即可回收其资源(第3.6.3.3节)。在此点之后,发送方可能会将相同的流ID用于新流。

Discussion: The flow sender detects that the flow is complete on receiving an acknowledgement of all fragment sequence numbers of the flow. This can't happen until after the receiver has detected that the flow is complete and acknowledged all of the sequence numbers. The receiver's RF_COMPLETE_LINGER period is two minutes (one Maximum Segment Lifetime (MSL)); this period allows any in-flight packets to drain from the network without being misidentified and gives the sender an opportunity to retransmit any sequence numbers if the completing acknowledgement is lost. The sender's F_COMPLETE_LINGER period is at least two minutes plus 10 seconds and doesn't begin until the completing acknowledgement is received; therefore, the same flow identifier won't be reused by the flow sender for a new sending flow for at least 10 seconds after the flow receiver has closed the receiving flow context. This ensures correct operation independent of network delay, even when the sender's clock runs up to 8 percent faster than the receiver's.

讨论:流发送器在收到流的所有片段序列号的确认时检测到流已完成。只有在接收器检测到流已完成并确认所有序列号后,才会发生这种情况。接收机的RF_完成_延迟周期为两分钟(一个最大段寿命(MSL));这段时间允许任何正在传输的数据包从网络中流出,而不会被错误识别,并且如果完成确认丢失,发送方有机会重新传输任何序列号。发送方的F_COMPLETE_逗留时间至少为2分钟加10秒,直到收到完成确认后才开始;因此,在流接收器关闭接收流上下文后至少10秒钟内,流发送器不会将相同的流标识符重新用于新的发送流。这确保了独立于网络延迟的正确操作,即使发送方的时钟运行速度比接收方快8%。

4. IANA Considerations
4. IANA考虑

This memo specifies chunk type code values (Section 2.3) and User Data option type code values (Section 2.3.11.1). These type code values are assigned and maintained by Adobe. Therefore, this memo has no IANA actions.

本备忘录规定了区块类型代码值(第2.3节)和用户数据选项类型代码值(第2.3.11.1节)。这些类型代码值由Adobe分配和维护。因此,本备忘录没有IANA行动。

5. Security Considerations
5. 安全考虑

This memo specifies a general framework that can be used to establish a confidential and authenticated session between endpoints. A Cryptography Profile, not specified herein, defines the cryptographic algorithms, data formats, and semantics as used within this framework. Designing a Cryptography Profile to ensure that communications are protected to the degree required by the application-specific threat model is outside the scope of this specification.

此备忘录指定了一个通用框架,可用于在端点之间建立机密和经过身份验证的会话。本文未指定的加密配置文件定义了在此框架内使用的加密算法、数据格式和语义。设计加密配置文件以确保通信受到特定于应用程序的威胁模型所要求的程度的保护不在本规范的范围内。

A block cipher in CBC mode is RECOMMENDED for packet encryption (Section 2.2.3). An attacker can predict the values of some fields from one plain RTMFP packet to the next or predict that some fields may be the same from one packet to the next. This SHOULD be considered in choosing and implementing a packet encryption cipher and mode.

分组加密建议使用CBC模式的分组密码(第2.2.3节)。攻击者可以预测从一个普通RTMFP数据包到下一个数据包的某些字段的值,或者预测从一个数据包到下一个数据包的某些字段可能相同。在选择和实现数据包加密和密码模式时应考虑这一点。

The well-known Default Session Key of a Cryptography Profile serves multiple purposes, including the scrambling of session startup packets to protect interior fields from undesirable modification by middleboxes such as NATs, increasing the effort required for casual passive observation of startup packets, and allowing different applications of RTMFP using different Default Session Keys to (intentionally or not) share network transport addresses without interference. The Default Session Key, being well known, MUST NOT be construed to contribute to the security of session startup; session startup is essentially in the clear.

众所周知的加密配置文件的默认会话密钥有多种用途,包括对会话启动数据包进行加扰,以保护内部字段不受NAT等中间盒的不希望的修改,从而增加偶然被动观察启动数据包所需的工作量,以及允许使用不同默认会话密钥的RTMFP的不同应用程序(有意或无意)在不受干扰的情况下共享网络传输地址。众所周知,默认会话密钥不得被解释为有助于会话启动的安全性;会话启动基本上是透明的。

Section 3.5.4.2 describes an OPTIONAL method for processing a change of network address of a communicating peer. Securely processing address mobility using that method, or any substantially similar method, REQUIRES at least that the packet encryption function of the Cryptography Profile (Section 2.2.3) employs a cryptographic verification mechanism comprising secret information known only to the two endpoints. Without this constraint, that method, or any substantially similar method, becomes "session hijacking support".

第3.5.4.2节描述了处理通信对等方网络地址更改的可选方法。使用该方法或任何实质上类似的方法安全地处理地址移动,至少要求加密配置文件(第2.2.3节)的分组加密功能采用加密验证机制,该机制包括仅两个端点已知的秘密信息。如果没有这个约束,该方法或任何实质上类似的方法将成为“会话劫持支持”。

Flows and packet fragmentation imply semantics that could cause unbounded resource utilization in receivers, causing a denial of service. Implementations SHOULD guard against unbounded or excessive resource use and abort sessions that appear abusive.

流和数据包碎片意味着语义可能会导致接收器中的无限资源利用率,从而导致拒绝服务。实现应防止无限或过度使用资源,并中止看似滥用的会话。

A rogue but popular Redirector (Section 3.5.1.4) could direct session initiators to flood a victim address or network with Initiator Hello packets, potentially causing a denial of service.

流氓但流行的重定向程序(第3.5.1.4节)可能会指示会话启动器将启动器Hello数据包淹没受害者地址或网络,从而可能导致拒绝服务。

An attacker that can passively observe an IHello and that possesses a certificate matching the Endpoint Discriminator (without having to know the private key, if any, associated with it) can deny the initiator access to the desired responder by sending an RHello before the desired responder does, since only the first received RHello is selected by the initiator. The attacker needn't forge the desired responder's source address, since the RHello is selected based on the tag echo and not the packet's source address. This can simplify the attack in some network or host configurations.

能够被动观察IHello并拥有与端点鉴别器匹配的证书(无需知道与其关联的私钥(如果有的话))的攻击者可以通过在所需响应者之前发送RHello来拒绝启动器对所需响应者的访问,因为只有第一个接收到的RHello由启动器选择。攻击者无需伪造所需响应者的源地址,因为RHello是根据标记回显而不是数据包的源地址选择的。这可以简化某些网络或主机配置中的攻击。

An attacker that can passively observe and record the packets of an established session can use traffic analysis techniques to infer the start and completion of flows without decrypting the packets. The User Data fragments of flows have unique sequence numbers, so flows are immune to replay while they are open. However, once a flow has completed and the linger period has concluded, the attacker could replay the recorded packets, opening a new flow in the receiver and duplicating the flow's data; this replay might have undesirable effects on the receiver's application. The attacker could also infer that a new flow has begun reusing the recorded flow's identifier and replay the final sequence number or any of the other fragments in the flow, potentially denying or interfering with legitimate traffic to the receiver. Therefore, the data integrity aspect of packet encryption SHOULD comprise anti-replay measures.

能够被动观察和记录已建立会话的数据包的攻击者可以使用流量分析技术推断流的开始和完成,而无需解密数据包。流的用户数据片段具有唯一的序列号,因此流在打开时不会重播。然而,一旦一个流已经完成,并且延迟期已经结束,攻击者就可以重放记录的数据包,在接收器中打开一个新的流并复制流的数据;此重播可能会对接收器的应用程序产生不良影响。攻击者还可以推断新流已开始重用记录流的标识符,并重播流中的最终序列号或任何其他片段,从而可能拒绝或干扰到接收方的合法流量。因此,数据包加密的数据完整性方面应包括防重放措施。

6. Acknowledgements
6. 致谢

Special thanks go to Matthew Kaufman for his contributions to the creation and design of RTMFP.

特别感谢Matthew Kaufman为RTMFP的创建和设计做出的贡献。

Thanks to Jari Arkko, Ben Campbell, Wesley Eddy, Stephen Farrell, Philipp Hancke, Bela Lubkin, Hilarie Orman, Richard Scheffenegger, and Martin Stiemerling for their detailed reviews of this memo.

感谢Jari Arkko、Ben Campbell、Wesley Eddy、Stephen Farrell、Philipp Hancke、Bela Lubkin、Hilarie Orman、Richard Scheffenegger和Martin Stiemering对本备忘录的详细审查。

7. References
7. 工具书类
7.1. Normative References
7.1. 规范性引用文件

[CBC] Dworkin, M., "Recommendation for Block Cipher Modes of Operation", NIST Special Publication 800-38A, December 2001, <http://csrc.nist.gov/publications/ nistpubs/800-38a/sp800-38a.pdf>.

[CBC]Dworkin,M.“分组密码操作模式的建议”,NIST特别出版物800-38A,2001年12月<http://csrc.nist.gov/publications/ nistpubs/800-38a/sp800-38a.pdf>。

[RFC0768] Postel, J., "User Datagram Protocol", STD 6, RFC 768, August 1980.

[RFC0768]Postel,J.,“用户数据报协议”,STD 6,RFC 768,1980年8月。

[RFC0791] Postel, J., "Internet Protocol", STD 5, RFC 791, September 1981.

[RFC0791]Postel,J.,“互联网协议”,STD 5,RFC 7911981年9月。

[RFC1122] Braden, R., "Requirements for Internet Hosts - Communication Layers", STD 3, RFC 1122, October 1989.

[RFC1122]Braden,R.,“互联网主机的要求-通信层”,标准3,RFC 1122,1989年10月。

[RFC2119] Bradner, S., "Key words for use in RFCs to Indicate Requirement Levels", BCP 14, RFC 2119, March 1997.

[RFC2119]Bradner,S.,“RFC中用于表示需求水平的关键词”,BCP 14,RFC 2119,1997年3月。

[RFC2460] Deering, S. and R. Hinden, "Internet Protocol, Version 6 (IPv6) Specification", RFC 2460, December 1998.

[RFC2460]Deering,S.和R.Hinden,“互联网协议,第6版(IPv6)规范”,RFC 2460,1998年12月。

[RFC2914] Floyd, S., "Congestion Control Principles", BCP 41, RFC 2914, September 2000.

[RFC2914]Floyd,S.,“拥塞控制原则”,BCP 41,RFC 2914,2000年9月。

[RFC4821] Mathis, M. and J. Heffner, "Packetization Layer Path MTU Discovery", RFC 4821, March 2007.

[RFC4821]Mathis,M.和J.Heffner,“打包层路径MTU发现”,RFC 48212007年3月。

[RFC5681] Allman, M., Paxson, V., and E. Blanton, "TCP Congestion Control", RFC 5681, September 2009.

[RFC5681]Allman,M.,Paxson,V.和E.Blanton,“TCP拥塞控制”,RFC 56812009年9月。

7.2. Informative References
7.2. 资料性引用

[RFC5389] Rosenberg, J., Mahy, R., Matthews, P., and D. Wing, "Session Traversal Utilities for NAT (STUN)", RFC 5389, October 2008.

[RFC5389]Rosenberg,J.,Mahy,R.,Matthews,P.,和D.Wing,“NAT的会话遍历实用程序(STUN)”,RFC 5389,2008年10月。

[ScalableTCP] Kelly, T., "Scalable TCP: Improving Performance in Highspeed Wide Area Networks", December 2002, <http://datatag.web.cern.ch/datatag/papers/ pfldnet2003-ctk.pdf>.

[ScalableTCP]Kelly,T.,“可扩展TCP:提高高速广域网的性能”,2002年12月<http://datatag.web.cern.ch/datatag/papers/ pfldnet2003 ctk.pdf>。

Appendix A. Example Congestion Control Algorithm
附录A.拥塞控制算法示例

As mandated in Section 3.5.2, an RTMFP is required to use TCP-compatible congestion control, but flexibility in exact implementation is allowed, within certain limits. This section describes an experimental window-based congestion control algorithm that is appropriate for real-time and bulk data transport in RTMFP. The algorithm includes slow start and congestion avoidance phases, including modified increase and decrease parameters. These parameters are further adjusted according to whether real-time data is being sent and whether Time Critical Reverse Notifications are received.

根据第3.5.2节的规定,RTMFP需要使用与TCP兼容的拥塞控制,但允许在某些限制范围内灵活执行。本节介绍一种实验性的基于窗口的拥塞控制算法,该算法适用于RTMFP中的实时和批量数据传输。该算法包括慢启动和拥塞避免阶段,包括修改的增加和减少参数。这些参数将根据是否发送实时数据以及是否接收到时间关键的反向通知进行进一步调整。

A.1. Discussion
A.1. 讨论

RFC 5681 defines the standard window-based congestion control algorithms for TCP. These algorithms are appropriate for delay-insensitive bulk data transport but have undesirable behaviors for delay- and loss-sensitive applications. Among the undesirable behaviors are the cutting of the congestion window in half during a loss event, and the rapidity of the slow start algorithm's exponential growth. Cutting the congestion window in half requires a large channel headroom to support a real-time application and can cause a large amount of jitter from sender-side buffering. Doubling the congestion window during the slow start phase can lead to the congestion window temporarily growing to twice the size it should be, causing a period of excessive loss in the path.

RFC 5681为TCP定义了标准的基于窗口的拥塞控制算法。这些算法适用于对延迟不敏感的批量数据传输,但在对延迟和丢失敏感的应用程序中存在不良行为。这些不良行为包括在丢失事件期间将拥塞窗口缩短一半,以及慢启动算法指数增长的速度。将拥塞窗口一分为二需要较大的信道净空以支持实时应用程序,并且可能会导致发送方缓冲的大量抖动。在慢速启动阶段将拥塞窗口加倍可能会导致拥塞窗口临时增大到其应有大小的两倍,从而导致在路径中出现一段时间的过度丢失。

We found that a number of deployed TCP implementations use the method of equation (3) from Section 3.1 of RFC 5681; this method, when combined with the recommended behavior of acknowledging every other packet, causes the congestion window to grow at approximately half the rate that the recommended method specifies. In order to compete fairly with these deployed TCPs, we choose 768 bytes per round trip as the increment during the normal congestion avoidance phase; this is approximately half of the typical maximum segment size of 1500 bytes and is also easily subdivided.

我们发现许多已部署的TCP实现使用RFC 5681第3.1节中等式(3)的方法;此方法与建议的每确认一个其他数据包的行为相结合时,会导致拥塞窗口以建议方法指定的大约一半的速率增长。为了与这些部署的TCP公平竞争,我们在正常拥塞避免阶段选择每往返768字节作为增量;这大约是1500字节典型最大段大小的一半,并且很容易细分。

The sender may be sending real-time data to the far end. When sending real-time data, a smoother response to congestion is desired while still competing with reasonable fairness to other flows in the Internet. In order to scale the sending rate quickly, the slow start algorithm is desired, but slow start's normal rate of increase can cause excessive loss in the last round trip. Accordingly, slow start's exponential increase rate is adjusted to double approximately every 3 round trips instead of every round trip. The multiplicative decrease cuts the congestion window by one eighth on loss to maintain a smoother sending rate. The additive increase is done at half the

发送方可能正在向远端发送实时数据。在发送实时数据时,需要对拥塞做出更平滑的响应,同时仍然与Internet中的其他流公平竞争。为了快速扩展发送速率,需要使用慢启动算法,但慢启动的正常增长速率可能会在最后一次往返中造成过度损失。相应地,慢启动的指数增长率调整为大约每3次往返翻倍,而不是每一次往返。乘法减少在丢失时将拥塞窗口缩短八分之一,以保持更平滑的发送速率。加法增加是以一半的速度完成的

normal rate (incrementing at 384 bytes per round trip), to both compensate for the less aggressive loss response and probe the path capacity more gently.

正常速率(以每次往返384字节的速度递增),以补偿不太严重的丢失响应,并更温和地探测路径容量。

The far end may report that it is receiving real-time data from other peers, or the sender may be sending real-time data to other far ends. In these circumstances (if not sending real-time data to this far end), it is desirable to respond differently than the standard TCP algorithms specify, to both yield capacity to the real-time flows and avoid excessive losses while probing the path capacity. Slow start's exponential increase is disabled, and the additive increase is done at half the normal rate (incrementing at 384 bytes per round trip). Multiplicative decrease is left at the normal rate (cutting by half) to yield to other flows.

远端可能报告它正在从其他对等方接收实时数据,或者发送方可能正在向其他远端发送实时数据。在这些情况下(如果不将实时数据发送到此远端),最好以不同于标准TCP算法规定的方式响应,以便在探测路径容量时既能为实时流提供容量,又能避免过度损失。慢启动的指数增长被禁用,并且加法增长以正常速率的一半完成(以每次往返384字节的速度递增)。乘法递减保持在正常速率(减半)以向其他流量屈服。

Since real-time messages may be small, and sent regularly, it is advantageous to spread congestion window increases out across the round-trip time instead of doing them all at once. We divide the round trip into 16 segments with an additive increase of a useful size (48 bytes) per segment.

由于实时消息可能很小,并且定期发送,因此有利于在往返时间内分散拥塞窗口的增加,而不是一次完成所有任务。我们将往返分为16个段,每个段增加一个有用的大小(48字节)。

Scalable TCP [ScalableTCP] describes experimental methods of modifying the additive increase and multiplicative decrease of the congestion window in large delay-bandwidth scenarios. The congestion window is increased by 1% each round trip and decreased by one eighth on loss in the congestion avoidance phase in certain circumstances (specifically, when a 1% increase is larger than the normal additive-increase amount). Those methods are adapted here. The scalable increase amount is 48 bytes for every 4800 bytes acknowledged, to spread the increase out over the round trip. The congestion window is decreased by one eighth on loss when it is at least 67200 bytes per round trip, which is seven eighths of 76800 (the point at which 1% is greater than 768 bytes per round trip). When sending real-time data to the far end, the scalable increase is 1% or 384 bytes per round trip, whichever is greater. Otherwise, when notified that the far end is receiving real-time data from other peers, the scaled increase is adjusted to 0.5% or 384 bytes per round trip, whichever is greater.

Scalable TCP[ScalableTCP]描述了在大延迟带宽情况下修改拥塞窗口的加性增加和乘性减少的实验方法。在某些情况下(特别是,当1%的增加量大于正常的附加增加量时),拥堵窗口在每次往返时增加1%,在拥堵避免阶段损失时减少八分之一。这里采用了这些方法。可扩展的增加量为每确认4800字节48字节,以在往返行程中分散增加。当拥塞窗口每次往返至少为67200字节时,拥塞窗口将在丢失时减少八分之一,即76800的八分之七(即每次往返1%大于768字节的点)。当向远端发送实时数据时,可伸缩增量为1%或每次往返384字节,以较大者为准。否则,当通知远端正在接收来自其他对等方的实时数据时,按比例增加将调整为每次往返0.5%或384字节,以较大者为准。

A.2. Algorithm
A.2. 算法

Let SMSS denote the Sender Maximum Segment Size [RFC5681], for example 1460 bytes. Let CWND_INIT denote the Initial Congestion Window (IW) according to Section 3.1 of RFC 5681, for example 4380 bytes. Let CWND_TIMEDOUT denote the congestion window after a timeout indicating lost data, being 1*SMSS (for example, 1460 bytes).

让SMS表示发送方的最大段大小[RFC5681],例如1460字节。根据RFC 5681第3.1节,让CWND_INIT表示初始拥塞窗口(IW),例如4380字节。让CWND_TIMEDOUT表示超时后的拥塞窗口,表示丢失的数据,即1*SMS(例如,1460字节)。

Let the session information context contain additional variables:

让会话信息上下文包含其他变量:

o CWND: the congestion window, initialized to CWND_INIT;

o CWND:拥塞窗口,初始化为CWND_INIT;

o SSTHRESH: the slow start threshold, initialized to positive infinity;

o SSTHRESH:慢启动阈值,初始化为正无穷大;

o ACKED_BYTES_ACCUMULATOR: a count of acknowledged bytes, initialized to 0;

o ACKED_BYTES_累加器:已确认字节的计数,初始化为0;

o ACKED_BYTES_THIS_PACKET: a count of acknowledged bytes observed in the current packet;

o ACKED_BYTES_此_数据包:在当前数据包中观察到的已确认字节数;

o PRE_ACK_OUTSTANDING: the number of bytes outstanding in the network before processing any acknowledgements in the current packet;

o PRE_ACK_Understand:在处理当前数据包中的任何确认之前,网络中未完成的字节数;

o ANY_LOSS: an indication of whether any loss has been detected in the current packet;

o ANY_LOSS:指示当前数据包中是否检测到任何丢失;

o ANY_NAKS: an indication of whether any negative acknowledgements have been detected in the current packet;

o ANY_NAKS:指示当前数据包中是否检测到任何否定确认;

o ANY_ACKS: an indication of whether any acknowledgement chunks have been received in the current packet.

o ANY_ACKS:当前数据包中是否接收到任何确认数据块的指示。

Let FASTGROW_ALLOWED indicate whether the congestion window is allowed to grow at the normal rate versus a slower rate, being false if a Time Critical Reverse Notification has been received on this session within the last 800 milliseconds (Sections 2.2.4 and 3.5.2.1) or if a Time Critical Forward Notification has been sent on ANY session in the last 800 milliseconds, and otherwise being true.

让FASTGROW_ALLOWED指示是否允许拥塞窗口以正常速率增长而不是以较慢速率增长,如果在最近800毫秒内在此会话上收到了时间关键型反向通知,则为false(第2.2.4节和第3.5.2.1节)或者,如果在过去800毫秒内已在任何会话上发送了时间关键型转发通知,则为true。

Let TC_SENT indicate whether a Time Critical Forward Notification has been sent on this session within the last 800 milliseconds.

让TC_SENT指示在过去800毫秒内是否在此会话上发送了时间关键型转发通知。

Implement the method described in Section 3.6.2.6 to manage transmission timeouts, including setting the TIMEOUT_ALARM.

实施第3.6.2.6节所述的方法来管理传输超时,包括设置超时报警。

On being notified that the TIMEOUT_ALARM has fired, perform the function shown in Figure 24:

收到超时报警已触发的通知后,执行图24所示的功能:

on TimeoutNotification(WAS_LOSS): set SSTHRESH to MAX(SSTHRESH, CWND * 3/4). set ACKED_BYTES_ACCUMULATOR to 0. if WAS_LOSS is true: set CWND to CWND_TIMEDOUT. else: set CWND to CWND_INIT.

超时通知时(WAS_丢失):将SSTHRESH设置为MAX(SSTHRESH,CWND*3/4)。将已确认字节数累加器设置为0。如果WAS\u LOSS为true:将CWND设置为CWND\u TIMEDOUT。否则:将CWND设置为CWND_INIT。

Figure 24: Pseudocode for Handling a Timeout Notification

图24:处理超时通知的伪代码

Before processing each received packet in this session:

在此会话中处理每个接收到的数据包之前:

1. Set ANY_LOSS to false;

1. 将任何_损失设置为false;

2. Set ANY_NAKS to false;

2. 将任何_nak设置为false;

3. Set ACKED_BYTES_THIS_PACKET to 0; and

3. 将此数据包的已确认字节设置为0;和

4. Set PRE_ACK_OUTSTANDING to S_OUTSTANDING_BYTES.

4. 将PRE_ACK_EXTABLE设置为S_EXTABLE_字节。

On notification of loss (Section 3.6.2.5), set ANY_LOSS to true.

在通知损失时(第3.6.2.5节),将任何损失设置为真。

On notification of negative acknowledgement (Section 3.6.2.5), set ANY_NAKS to true.

在通知否定确认(第3.6.2.5节)时,将任何_NAKS设置为true。

On notification of acknowledgement of data (Section 3.6.2.4), set ANY_ACKS to true, and add the count of acknowledged bytes to ACKED_BYTES_THIS_PACKET.

在数据确认通知(第3.6.2.4节)中,将任何_ACKS设置为true,并将已确认字节的计数添加到此_数据包的已确认_字节。

After processing all chunks in each received packet for this session, perform the function shown in Figure 25:

在此会话中处理每个接收数据包中的所有数据块后,执行图25所示的功能:

if ANY_LOSS is true: if (TC_SENT is true) OR (PRE_ACK_OUTSTANDING > 67200 AND \ FASTGROW_ALLOWED is true): set SSTHRESH to MAX(PRE_ACK_OUTSTANDING * 7/8, CWND_INIT). else: set SSTHRESH to MAX(PRE_ACK_OUTSTANDING * 1/2, CWND_INIT). set CWND to SSTHRESH. set ACKED_BYTES_ACCUMULATOR to 0. else if (ANY_ACKS is true) AND (ANY_NAKS is false) AND \ (PRE_ACK_OUTSTANDING >= CWND): set var INCREASE to 0. var AITHRESH. if FASTGROW_ALLOWED is true: if CWND < SSTHRESH: set INCREASE to ACKED_BYTES_THIS_PACKET. else: add ACKED_BYTES_THIS_PACKET to ACKED_BYTES_ACCUMULATOR. set AITHRESH to MIN(MAX(CWND / 16, 64), 4800). while ACKED_BYTES_ACCUMULATOR >= AITHRESH: subtract AITHRESH from ACKED_BYTES_ACCUMULATOR. add 48 to INCREASE. else FASTGROW_ALLOWED is false: if CWND < SSTHRESH AND TC_SENT is true: set INCREASE to CEIL(ACKED_BYTES_THIS_PACKET / 4). else: var AITHRESH_CAP. if TC_SENT is true: set AITHRESH_CAP to 2400. else: set AITHRESH_CAP to 4800. add ACKED_BYTES_THIS_PACKET to ACKED_BYTES_ACCUMULATOR. set AITHRESH to MIN(MAX(CWND / 16, 64), AITHRESH_CAP). while ACKED_BYTES_ACCUMULATOR >= AITHRESH: subtract AITHRESH from ACKED_BYTES_ACCUMULATOR. add 24 to INCREASE. set CWND to MAX(CWND + MIN(INCREASE, SMSS), CWND_INIT).

如果任何丢失为真:如果(TC发送为真)或(预确认未完成>67200且\FASTGROW允许为真):将SSTHRESH设置为最大值(预确认未完成*7/8,CWND初始)。否则:将SSTHRESH设置为MAX(预确认未完成*1/2,CWND初始)。将CWND设置为SSTHRESH。将已确认字节数累加器设置为0。否则如果(任何确认为真)和(任何确认为假)和\(预确认>=CWND):将var增加设置为0。var AITHRESH。如果FASTGROW\u ALLOWED为true:如果CWND<SSTHRESH:将增加设置为ACKED\u BYTES\u此\u数据包。否则:将此数据包添加到已确认字节累加器。将AITHRESH设置为最小值(最大值(CWND/16,64),4800)。当已确认字节\u累加器>=AITHRESH时:从已确认字节\u累加器中减去AITHRESH。加48以增加。else FASTGROW_ALLOWED为false:如果CWND<SSTHRESH且TC_SENT为true:则将递增设置为CEIL(已确认字节数\u此\u数据包/4)。其他:var AITHRESH_帽。如果发送的TC_为真:将AITHRESH_上限设置为2400。否则:将AITHRESH_上限设置为4800。将此数据包添加到已确认字节累加器。将AITHRESH设置为最小值(最大值(CWND/16,64),AITHRESH_上限)。当已确认字节\u累加器>=AITHRESH时:从已确认字节\u累加器中减去AITHRESH。加24以增加。将CWND设置为最大(CWND+MIN(增加,SMSS),CWND_INIT)。

Figure 25: Pseudocode for Congestion Window Adjustment after Processing a Packet

图25:处理数据包后拥塞窗口调整的伪代码

Author's Address

作者地址

Michael C. Thornburgh Adobe Systems Incorporated 345 Park Avenue San Jose, CA 95110-2704 US

美国加利福尼亚州圣何塞公园大道345号迈克尔·C·桑伯格Adobe系统公司,邮编95110-2704

   Phone: +1 408 536 6000
   EMail: mthornbu@adobe.com
   URI:   http://www.adobe.com/
        
   Phone: +1 408 536 6000
   EMail: mthornbu@adobe.com
   URI:   http://www.adobe.com/