共计 19543 个字符,预计需要花费 49 分钟才能阅读完成。
欢迎关注公众号: nullobject。
文章首发在个人博客 https://www.nullobject.cn,公众号 nullobject 同步更新。
PTP/IP (PTP over IP) 是一个通过 IP 连接, 建立在 Picture Transfer Protocol (PTP) 上的传输层
英文原版协议下载
0 说明
本文档由 nullobject 对应 PTP-IP 标准协议 1.0 版本进行学习整理,原版协议为英文版,学习时依靠自己理解和使用有道云翻译,对理解不到位、翻译有问题的地方麻烦批评指正。—— by nullobject in 2019-06-03 15:29
1 PTP-IP 协议简介
1.1 目的
本文档描述了一个基于 IP 网络的 ISO-15740/PIMA 1574:2000/ 图片传输协议 (PTP) 的实现。
PTP 被设计用来提供与数字静止摄影设备的标准通信。该协议指定了标准的图像引用行为、操作、响应、事件、设备属性、数据集和数据格式,以确保互操作性,还提供了可选的操作和格式,以及扩展机制。
1.2 格式规范
The key words“MUST”,“MUST NOT”,“REQUIRED”,“SHALL”,“SHALL NOT”,“SHOULD”,“SHOULD NOT”,“RECOMMENDED”,“NOT RECOMMENDED”,“MAY”,“OPTIONAL”in this document are to be interpreted as described in“Key words for use in RFCs to Indicate Requirement Levels”[5].
1.3 参考
下表列举了本文档的参考资料:
ID/Description |
---|
[1] PTP protocol, PIMA 15740:2000 |
[2] Computer Networks, Andrew S. Tanenbaum, ISBN:0130661023, Prentice Hall Aug 09,2002 |
[3] UPnP Standard, http://www.upnp.org/resources/documents.asp |
[4] ZeroConf Standard, http://www.zeroconf.org |
[5] Formatting Conventions. http://www.faqs.org/rfcs/rfc21129.html |
1.4 手写字母缩写和缩写词
缩写 | 含义 |
---|---|
TCP | Transfer Control Protocol |
UDP | User Datagram Protocol |
IP | Internet Procotol |
PnP | Plug and Play |
PTP | Picture Transfer Protocol |
PTP-IP | IP Picture Transfer Protocol |
PIMA | Photographic and Imaging Manufacture Association |
DHCP | Dynamic Host Configuration Protocol |
v4LL | IPv4 Link-Local Address |
1.5 参与人员
- Petronel Bigioi – FotoNation Ireland
- George Susanu – FotoNation Ireland
- Alexei Pososin – FotoNation Ireland
- Denis McHugh – FotoNation Ireland
- Eran Steinberg – FotoNation US
- Yury Prilusky – FotoNation US
1.6 照片传输协议 (“PTP”) 条款
PTP 规范定义了设备角色、操作、图像格式和其他相机特定的数据类型和结构。在 PTP 的 TCP/IP 实现中,所有术语和定义都按照 PTP 规范中定义的那样使用。
1.6.1 设备规则
从通信的角度来看,设备可以充当启动器设备 (Initiator) 或响应端设备(Responder),启动器设备相当于一个客户端,响应端设备相当于服务端。启动器设备是向响应端设备发起操作请求的设备。响应端设备则是能够响应这些操作请求的设备。一个设备可能只是一个启动器设备,或者只是一个响应端设备,或者两者兼备,但不能在同一个设备连接上同时担任两种角色。
操作请求只能由启动器设备发起;事件被响应端设备用于把有关它状态的改变通知启动器设备。
1.6.2 会话(Session)
根据 PTP 协议,会话被定义为两个设备之间的逻辑连接,操作和事件事务可以通过该逻辑连接进行通信。根据 PTP 规范,一个响应端设备可以支持多个并发会话,每个会话都有自己的状态。
当启动器设备请求 OpenSession 操作事务时将会打开一个会话,并且使用响应端设备发出的一个有效响应成功结束该请求。
会话将在启动器设备请求 CloseSession 操作事务时被关闭,并且使用响应端设备发出的一个有效响应成功结束该请求。当启动器设备和响应端设备之间的连接被关断开时会话也会被关闭(例如通信超时)。
大多数操作需要在一个开放会话上下文中执行。不过,不需要打开会话就可以通过 GetDeviceInfo 操作获取设备功能。
支持多会话的设备必须能够使它们彼此保持异步和不透明。
1.6.3 会话 ID(SessionID)
通常,如果使用相同传输级别的通信通道,则会话 ID 旨在使响应端设备能够按适当的顺序分发来自不同启动器设备的请求。对于打开不同通信通道的传输,对于每个会话,不需要重新设置会话 ID,因为响应端设备将能够处理多个会话。
PTP 的 PTP- IP 传输实现不会将会话 ID 发送到响应端设备。响应端设备可以通过控制它允许的最大 PTP- IP 连接数来限制并发 PTP 会话的数量。
如果启动器设备的 PTP-IP 层发现响应端设备不接受新的 PTP-IP 连接,它将向 PTP 层发送传输特定的错误代码。在建立传输指定连接之后,启动端设备可以向远程响应端设备发出 GetDeviceInfo 和OpenSession请求。在这个阶段中,响应端设备可能返回一个 设备繁忙 (Device_Busy) 的 PTP 错误作为对 OpenSession 的响应(如果响应端设备对它能够支持的并发 PTP 会话的数量有限制)。在这种情况下,启动端设备应该释放 PTP 连接,并稍后重试。
1.6.4 事务(Transactions)
事务 是 PTP 协议中操作的基本单位,PTP 协议规定的所有操作都基于事务进行。事务操作请求由启动器设备 (Initiator) 发起,传送到到响应端设备 (Responder),在一个会话(Session) 中,同一时间只能有一个事务操作在执行,操作事务在一个会话中默认是同步的。
一个事务通常由三个阶段组成:Operation Request、Operation Response、Data Phase,如下图:
取决于事务操作本身,Data Phase这一可选阶段可能不会存在于一个事务流程中,即事务只有 Operation Request 和Operation Response。而当事务中存在 Data Phase 时,数据可能从初始化器 Initiator 发送到响应设备Responder(即I–>R),或者反过来R–>I,但同一个操作中数据只能在一个方向上传输。
1.6.5 事务 ID(TransactionID)
事务 ID(TransactionID)用于在一个给定的会话中标识不同事务,与在 PTP 协议的第 9.3.1 项中定义的事务 ID 相同,是一个 32 位无符号整型数字。事务 ID 在给定的会话中是唯一且连续的数字序列,其范围从 0x00000001 到 0xFFFFFFFE,0x00000000 和 0xFFFFFFFF 作为保留值不被使用。
1.7 与 PTP 协议一致性
在 PTP 标准协议的 7[1] 节中,为底层传输层定义了这些需求。
- PTP 标准协议 7.1节:断开事件。PTP 协议的这一节要求传输层必须向上层的报告设备断开。这是通过 PTP-IP 层生成设备断开通知来实现的。
- PTP 标准协议 7.2节:稳定、无错误通道。PTP 协议的这节要求需要可靠,无错误的通道。在 PTP-IP 中,这通过使用配置了 Keep Alive 选项的 TCP 连接来实现。
- PTP 标准协议 7.3节:异步事件的支持。PTP 要求支持异步事件,在 PTP-IP 中,事件连接被定义为用于传输异步事件,并且与命令 / 数据通道是异步的。
- PTP 标准协议 7.4节:设备发现和枚举。PTP 要求支持设备发现和枚举服务,在 PTP-IP 中,设备发现和枚举使用对 IP 网络可用的通用解决方案来实现,可以使用一个基于设备发现协议 [5] 的自定义 UDP 协议。
- PTP 标准协议 7.5节:传输特定。PTP 要求图像设备传输的实现符合相关机构发布的特定使用传输规范。本文档说明了如何使用位于 TCP/IP 协议栈上层的 PTP-IP 传输。
2 PTP-IP 实现
2.1 PTP-IP 协议模型
在 PTP-IP 的实现中,用户程序与 PTP-IP 层之间的通信基于 PTP 事务模型实现,参考 PTP 协议的 9.3[1] 节,该通信模型如下图:
本文档的目的在于制定和说明 PTP-IP 通信协议,应用程序和 PTP-IP 层(编程接口,API)之间交互的实现并不在本文档的内容范围内。本文档仅以互操作性的方式规定两个 PTP-IP 实体之间的通信。不过,PTP 层(用户应用程序)和 PTP-IP 层之间的接口可能由以下基本类型组成:
-
操作请求(Operation Request)
每当进行请求操作时,启动器设备 (Initiator) 中的应用程序就会发送一个操作请求,随即该请求被响应端设备 (Responder) 接受。操作请求中通常包含一组与该操作相关的参数。
-
操作响应(Operation Responses)
每当接收到一个操作请求,响应端设备 (Responder) 会发送一个操作响应作为该操作请求的回应。对于启动器设备 (Initiator) 中应用程序发起的每个操作请求,都需要回复一个操作响应。操作响应中总是会包含其对应的操作请求的 结果代码,并且可能会包含一组参数。
-
数据读入(Data-In)
数据读入 (Data-In) 是相对于用于应用程序而言的,即数据流向是从响应端设备 (Responder) 到启动器设备(Initiator)。
-
数据写出(Data-Out)
数据写出 (Data-Out) 的数据流与数据读入 (Data-In) 相反。
-
事件(Events)
PTP-IP 中的事件是指有关响应端设备 (Responder) 的状态变更的通知,事件由响应端设备启动。
-
设备连接 / 断开(Device Connect/Disconnect)
设备的连接 / 断开是平台相关类型的事件。这两个事件并不直接在启动器设备和响应端设备之间通信,而是当检测到设备被连接 / 断开时由各自的 PTP-IP 层生成。
操作和事件两种事务的类型的定义在 PTP 协议文档的 10.11、12 [1] 节中可以找到,并且 PTP 协议在 14 [1] 节中为设备标准的一致性确定了一组操作和事件。
2.2 PTP-IP 传输模型
PTP 标准协议文档的 7 [1] 节定义了 PTP 标准传输需求,而 PTP-IP 则是基于使用 TCP 层作为传输层实现:
与 PTP 一样,PTP-IP 也期望从其传输层获得可靠、稳定无错误的通信通道,而 TCP(位于 TCP/IP 协议栈中)正是可以满足这些需求的自然传输层。TCP 是一个基于流的传输层,它提供多个通信通道 (TCP Connection) 和无错误的数据传输。
在 PTP-IP 中,两个设备之间的所有通信都通过两个 TCP 连接 (逻辑数据通道) 进行:
由于事件本身具有异步性质,事件的数据包与操作 / 数据事务数据包分开分别通过两个单独的通道传输。
2.2.1 命令 / 数据连接(Command/Data TCP Connection)
PTP-IP 的 命令 / 数据连接用于传输 PTP 操作请求、响应和数据事务,以及特定于 PTP-IP 的数据包。该连接由启动器设备 (Initiator) 建立,并标志本地及响应端设备 (Responder) 的 IP 地址和端口号。响应端设备 (Responder) 的 IP 地址和端口号通常是通过 设备发现机制 来确定。
2.2.2 事件连接(Event TCP Connection)
PTP-IP 的事件连接作为启动器设备 (Initiator) 开启的与响应端设备 (Responder) 之间的第二个连接,用于传输 PTP 事件,以及特定于 PTP-IP 的数据包。与命令 / 数据连接相同,事件连接由启动器设备 (Initiator) 发起建立,并标志本地和响应端设备 (Responder) 的 IP 地址和端口号,响应端设备 (Responder) 的 IP 地址和端口号通常是通过设备发现机制来确定。
2.2.3 传输通道管理
2.2.3.1 建立 PTP-IP 连接
在启动器设备 (Initiator) 与响应端设备 (Responder) 之间的通信中,每当需要这些传输通道时,启动器设备 (Initiator) 将负责发起与响应端设备 (Responder) 的 PTP-IP/TCP 连接。如前文所述,PTP-IP 的传输通道使用 TCP 连接实现:一个通道用于命令 / 数据传输,另一个则用于事件传输。每个通道都会标志本地以及响应端设备 (Responder)IP 地址和端口号。从 PTP-IP 的通信模型中可以看到,启动器设备(Initiator) 的 PTP-IP 实际上是一个 TCP 客户端,对应地响应端设备 (Responder) 的 PTP-IP 则是一个 TCP 服务器。响应端设备 (Responder) 轮询等待连接请求,并且预定义 (或者动态分配) 了一个 TCP 连接端口号.PTP-IP 服务端默认端口号为 15740。PTP-IP 连接建立过程:
PTP-IP 中的 TCP 连接应遵循上图所示顺序进行:
- 启动器设备 (Initiator) 发起命令 / 数据的 TCP 连接:指定响应端设备 (Responder) 的IP 地址 和端口号,并连接到响应端设备(Responder);
- TCP 连接建立成功后,启动器设备 (Initiator) 立即发送一个 Init Command Request 包,数据包中需要包含启动器设备 (Initiator) 的唯一标识(GUID 和启动器设备的用户友好名称),例如:
- 响应端设备 (Responder) 程序根据实际情况,回复启动器设备一个 Init Command Ack 包以告知启动器设备请求成功并且可以继续进行连接;或者回复 Init Fail 数据包表示请求失败,以告知启动器设备请求访问被拒绝,并且断开命令 / 数据的 TCP 连接,同时启动器设备接收到请求失败的回应后也应该断开相应的的命令 / 数据连接。
- 启动器设备 (Initiator) 接收到 Init Command Ack 包后,继续发起一个事件的 TCP 连接:指定响应端设备 (Responder) 的IP 地址 和端口号 ,并连接到响应端设备(Responder)。 注意该连接与第 1 步中的连接是区别开的。
- 一旦连接建立成功,启动器设备 (Initiator) 立即发送一个 Init Event Request 包,数据包需要包含第 4 步骤中接收到的 连接号 (Connection Number)。响应端设备(Responder) 需要根据这个连接号将 命令 / 数据 和事件 两个 TCP 连接关联同一个 PTP-IP 连接和同一个 PTP 会话。
- 与步骤 3 类似,请求成功则回复一个 Init Event Ack 包,在响应端设备 (Responder) 资源不足时,回复 Init Fail 包告知启动端请求失败。
- 一旦启动器设备 (Initiator) 接收到步骤 6 中回传的 Init Event Ack 包则认为请求成功,此时 PTP-IP 连接真正建立完成,接着即可进行进一步的数据通信。
在第二个 TCP 连接 (事件连接) 建立失败的情况下,第一个 TCP 连接 (命令 / 数据连接) 需要被关闭,稍后启动器设备 (Initiator) 应再次尝试建立 PTP-IP 连接。建议每次创建 PTP-IP 连接的时间间隔为 30s。
2.2.3.2 传输通道配置
根据 PTP 协议 7 [1] 节,PTP-IP 层要求传输通道可靠、无错误。这种传输通道可以通过正确配置 TCP 连接来实现。
PTP-IP 的 TCP 连接应该使用一下选项创建:
- Keep Alive 选项:启动器和响应端需要同时需要同时开启这个选项,以确保两端的 TCP 实体在非活跃时期能够维持连接。开启这个选项后,启动器和响应端各自的 TCP 栈会通过 TCP 协议特定的方式来检查所配对的设备是否仍旧能够响应。这种检查方式是在 TCP 层进行,对上层的 PTP-IP 来说是透明的。
- 禁用 Nagle 算法:需要在启动器和响应端程序的 TCP/IP 协议栈上禁用 Nagle 算法,以避免在传输命令代码和响应时出现不必要的延迟。
总的来说就是需要设置如下选项(Qt 为例):
// 禁用 Nable 算法
mTcpSocket->setSocketOption(QAbstractSocket::SocketOption::LowDelayOption,1);
// 开启 Keep Alive 选项
mTcpSocket->setSocketOption(QAbstractSocket::SocketOption::KeepAliveOption,1);
2.2.3.3 关闭 PTP-IP 连接
当不再需要 PTP-IP 时,由启动器设备 (Initiator) 关闭连接。当启动器设备 (Initiator) 或者响应端设备 (Responder) 在打开的传输通道上发生错误而导致这些通道不稳定时,也应关闭 PTP-IP 连接。关闭 PTP-IP 连接时两个 TCP 连接 (命令 / 数据连接和事件连接) 都必须要关闭。
2.3 传输的数据包类型
本节主要介绍用于在启动器设备 (Initiator) 和响应端设备 (Responder) 间通信的一组数据包类型。PTP-IP 的数据包类型相当于 PTP 协议中定义的 操作请求 (Operation Request)、 响应 (Response)、 数据 (Data) 和事件 (Event) 事务类型。PTP-IP 数据包中的所有多字节值都使用 小端 (Little-Endian) 格式表示,通常一个 PTP-IP 数据包的格式如下:
Field | Size[Bytes] | Data Type |
---|---|---|
Length | 4 | UINT32 |
Packet Type | 4 | UINT32 |
Payload | 根据 Length 计算 | ? |
- 长度 (Length):4 字节,长度参数决定了包含包头在内的整个数据包的大小;
- 包类型 (Packet Type):4 字节,该字段标志了数据包的类型,该参数有下列可选的值:0x0000NNNN* 表示隐藏值。
Value | Description |
---|---|
0x00000000 | 保留值 |
0x0000NNNN* | Init Command Request Packet |
0x0000NNNN* | Init Command Ack |
0x0000NNNN* | Init Event Request Packet |
0x0000NNNN* | Init Event Ack Packet |
0x0000NNNN* | Init Fail Packet |
0x0000NNNN* | Operaqion Request Packet |
0x0000NNNN* | Operation Response Packet |
0x0000NNNN* | Event Packet |
0x0000NNNN* | Start Data Packet |
0x0000NNNN* | Data Packet |
0x0000NNNN* | Cancel Packet |
0x0000NNNN* | End Data Packet |
0x0000NNNN* | Probe Request Packet |
0x0000NNNN* | Probe Response Packet |
0x0000NNNN* – 0xFFFFFFFF | 保留值 |
- 负载(Payload):包含协议更上层的或者是传输特定的数据。
2.3.1 Init Command Request Packet
该数据包在命令 / 数据传输通道被建立后立即被启动器设备 (Initiator) 发送。该数据包通过命令 / 数据连接传输,用于通知响应端设备 (Responder) 对启动器进行标识,从而使响应端设备 (Responder) 能够实现过滤机制。数据包结构如下:
Field | Size[Bytes] | Data Type |
---|---|---|
Length | 4 | UINT32 |
Packet Type | 4 | UINT32 |
Initiator GUID | 16 | UINT8 |
Initiator Friendly Name | Variable | UINT16 |
Initiator Protocol Version | 4 | UINT32 |
- Initiator GUID:16字节,启动器设备的全局唯一标识符;
- Initiator Friendly Name:启动器设备的用户友好名称,该字段是一个包含启动器设备描述信息的 Unicode 字符串,该字串通常用于响应端设备的 UI 显示上(以确认或拒绝来自给定启动器设备的连接请求);
- Initiator Protocol Version:4字节,启动器设备端实现的协议版本号。该字段由一个主版本号 (高 16 位) 和一个子版本号 (低 16 位) 组成。该字段应该被设置成第 3 节中定义的BINARY PROTOCOL VERSION。
- 启动器设备的 GUID 和响应端设备的 GUID 可用于进行设备绑定。若启动器设备的 GUID 的 16 个字节全由 0xFF 组成,则表示该启动器设备是一个 匿名 设备,此时由响应端设备决定是否允许连接。更多信息参考 附录 5.3。
- 启动器设备的用户友好名称是一个以 空(NULL)字符结尾的 Unicode 字符串。包括结尾的空字符,其最大长度位 40 个字节。不使用该字段时,必须使用一个 空(NULL)字符填充该字段。
数据包示例:
对应地:
- 30 00 00 00:第 0~3 字节表示 Length 字段
- 01 00 00 00:第 4~7 字节表示 Packet Type 字段
- fc 47 f8 4e 30 97 ee 64 1c 26 38 ae b0 1a 9e ac:第 8~23 字节表示 Initiator GUID 字段
- 44 00 53 00 43 00 2d 00 52 00 58 00 30 00 4d 00 32 00 00 00:第 24~(Length-4-4-16-4-1) 字节表示 Initiator Friendly Name 字段
- 00 00 01 00:最后 4 字节表示 Initiator Protocol Version 字段。
2.3.2 Init Command ACK Packet
该数据包由响应端设备 (Responder) 回传给启动器设备,以响应启动器设备发送的 Init Command Request Packet,并为接下来的 PTP-IP 会话分配一个 连接号(Connection Number),该数据包在命令 / 数据连接上传输。
包结构如下:
Field | Size[Bytes] | Data Type |
---|---|---|
Length | 4 | UINT32 |
Packet Type | 4 | UINT32 |
Connection Number | 4 | UINT32 |
Responder GUID | 16 | UINT6 |
Responder Friendly Name | Variable | UINT16 |
Responder Protocol Version | 4 | UINT32 |
- Connection Number:连接号 ,是响应端设备生成的用于关联所有属于同一个 PTP 会话的 TCP 连接通道的 唯一值。
- Responder GUID:响应端设备的 GUID。
- Responder Friendly Name:响应端设备的用户友好名称,可用于启动器设备端的 UI 显示。
- Responder Protocol Version:响应端设备实现的协议版本号。该字段由一个主版本号 (高 16 位) 和一个子版本号 (低 16 位) 组成。该字段应该被设置成第 3 节中定义的BINARY PROTOCOL VERSION。
- 响应端设备的用户友好名称是一个以 空(NULL)字符结尾的 Unicode 字符串。包括结尾的空字符,其最大长度位 40 个字节。不使用该字段时,必须使用一个 空(NULL)字符填充该字段。
- 连接号在启动器设备和响应端设备连接被建立的期间保持有效。一旦响应端设备成功关联属于同一个 PTP-IP 连接的两个 TCP 连接,连接号即可被重新使用。
实际该数据包结构看起来如下:
对应地:
- 34 00 00 00:第 0~3 字节表示 Length 字段
- 02 00 00 00:第 4~7 字节表示 Packet Type 字段
- 01 00 00 00:第 8~11 字节表示 Connection Number 字段
- 00 00 00 00 00 00 00 00 ff ff 10 98 c3 d1 5f 45:第 12~27 字节表示 Responder GUID 字段
- 44 00 53 00 43 00 2d 00 52 00 58 00 30 00 4d 00 32 00 00 00:第 28~(Length-4-4-4-16-4-1) 字节表示 Responder Friendly Name 字段
- 00 00 01 00:最后 4 字节表示 Responder Protocol Version 字段。
2.3.3 Init Event Request Packet
命令 / 数据 连接被成功建立后,该数据包被启动器设备发送至响应端设备用于建立 事件 连接。启动器设备在接收到一个有效的 Init Command Ack Packet 数据包后,立即建立事件的 TCP 连接并发送 Init Event Request Packet 数据包,包中携带的连接号即前面步骤中接收到的在 Init Command Ack 数据包中返回的连接号。Init Event Request数据包通过 事件 连接传输。
包结构如下:
Field | Size[Bytes] | Data Type |
---|---|---|
Length | 4 | UINT32 |
Packet Type | 4 | UINT32 |
Connection Number | 4 | UINT32 |
- Connection Number:连接号 ,从Init Command Ack Packet 包数据中获得。
数据包示例:
对应地:
- 0c 00 00 00:第 0~3 字节表示 Length 字段
- 03 00 00 00:第 4~7 字节表示 Packet Type 字段
- 01 00 00 00:第 8~11 字节表示 Connection Number 字段
2.3.4 Init Event ACK Packet
该数据包由响应端设备 (Responder) 通过 事件 连接通道回传给启动器设备,以告知启动器设备 PTP-IP 连接建立成功。
包结构如下:
Field | Size[Bytes] | Data Type |
---|---|---|
Length | 4 | UINT32 |
Packet Type | 4 | UINT32 |
数据包示例:
对应地:
- 08 00 00 00:第 0~3 字节表示 Length 字段
- 04 00 00 00:第 4~7 字节表示 Packet Type 字段
2.3.5 Init Fail Packet
初始化失败数据包 。当 PTP-IP 连接建立失败时,该数据包由响应端设备(Responder) 回传给启动器设备,以告知启动器设备连接建立失败及失败原因,失败原因被记录在 Reason 字段。接收到该数据包之后,启动器设备 必须 关闭先前步骤中建立的命令 / 数据连接。该数据包发出后,响应端设备亦应关闭相应的 PTP-IP 连接 (由启动器设备发起的被拒绝的 TCP 连接)。Init Fail Packet 可以通过任意的 TCP 连接传输。更多有关 PTP-IP 连接的建立可以参考 PTP-IP 连接一节内容。
Field | Size[Bytes] | Data Type |
---|---|---|
Length | 4 | UINT32 |
Packet Type | 4 | UINT32 |
Reason | 4 | UINT32 |
Reason字段包含了连接拒绝的错误码,该字段定义的错误码有以下几种:
- 0x0000NNNN*:FAIL_REJECTED_INITIATOR,表示响应端设备实现了一个设备绑定的机制,但请求连接的启动器设备不在允许的设备集合内。参考 附录 5.3了解绑定机制详情。
- 0x0000NNNN*:FAIL_BUSY,表示响应端设备繁忙:响应端设备的活动连接数过多。启动器设备可以稍后再尝试连接。
- 0x0000NNNN*:FAIL_UNSPECIFIED,其他原因。
2.3.6 Operation Request Packet
操作请求数据包 。该数据包在 PTP-IP 协议中用于传输在 PTP 标准协议9.3.2 [1] 节定义的 PTP 操作请求。PTP-IP Operation Request Packet由启动器设备发送至响应端设备,并通过命令 / 数据通道传输。
包结构如下:
Field | Size[Bytes] | Data Type |
---|---|---|
Length | 4 | UINT32 |
Packet Type | 4 | UINT32 |
Data Phase Info | 4 | UINT32 |
Operation Code | 2 | UINT16 |
TransactionID | 4 | UINT32 |
Parameter1 | 4 | UINT32 |
Parameter2 | 4 | UINT32 |
Parameter3 | 4 | UINT32 |
Parameter4 | 4 | UINT32 |
Parameter5 | 4 | UINT32 |
-
Data Phase Info:指示下一个数据阶段是 数据写 (data out) 阶段还是 数据读 / 数据 (data in/no) 阶段,该字段值被定义为下列几种:
- 0x0000NNNN*:无数据或数据读 (data in/no) 阶段:启动器设备不知道响应端设备是否会提供一些数据或者提供一个响应;
- 0x0000NNNN*:数据写 (data out) 阶段
- 0x0000NNNN*:未知的数据阶段
- Operation Code:操作码 ,包含定义在 PTP 标准协议 第 10.2 和 10.3 [1]节的 PTP 操作码。
- TransactionID:事务 ID,它在当前连接的响应端设备的开放会话上下文中是唯一的,如 PTP 第 9.3.1 [1] 节中定义。TransactionID 是一个从 0x00000000 到 0xFFFFFFFF 的连续数值。0x00000000 作为特殊的值,只能被用于 OpenSession 或GetDeviceInfo两个操作请求,每次当此参数不适用于包时,必须使用另一个特殊值 0xFFFFFFFF。
- Parameter 1~5:这些字段包含特定于操作的参数,这些参数的解释取决于 操作码 (Operation Code) 参数,一个操作最多可以容纳 5 个参数。这些参数的使用方式定义在 PTP 标准协议的 10.1 和 10.4 [1] 节。
- 如果 Data Phase Info 字段被设置为 Data Out Phase,则在发送该数据包后接着必须要发送一个Start Data Packet 包。
- 如果启动器设备需要发送空数据对象到响应端设备,有两个选项可选:1.将 Data Phase Info 字段设置为 No data or data in phase,在这情况下响应端设备将会直接回应一个Operation Response Packet 包,而不会等待 Data Packet;2. 将Data Phase Info字段设置为 Data out Phase. 在这种情况下,数据写阶段(data out phase) 必须只包含一个 Start Data Packet 包,并将该包的 Total Data Length 字段设置为 0x00000000,并且启动器设备必须不能发送后续的 End Data Packet 数据包。
实际该数据包结构如下:
对应地:
- 16 00 00 00:第 0~3 字节表示 Length 字段
- 06 00 00 00:第 4~7 字节表示 Packet Type 字段
- 02 00 00 00:第 8~11 字节表示 Data Phase Info 字段
- 05 92:第 12~13 字节为 Operation Code 字段
- 06 00 00 00:第 14~17 字节为 Transaction ID 字段
- 0e 50 00 00:第 18~21 字节为 Parameter 1 字段
2.3.7 Operation Response Packet
操作响应数据包 。该数据包在 PTP-IP 协议中用于传输在 PTP 标准协议9.3.4 [1] 节定义的 PTP操作响应 。PTP-IP Operation Response Packet 数据包由响应端设备通过命令 / 数据通道回应给启动器设备。操作响应 数据包仅在需要指示操作请求事务已经结束并且需要传递操作结果时才由响应端设备发送给启动器设备。
包结构如下:
Field | Size[Bytes] | Data Type |
---|---|---|
Length | 4 | UINT32 |
Packet Type | 4 | UINT32 |
Response Code | 2 | UINT16 |
TransactionID | 4 | UINT32 |
Parameter1 | 4 | UINT32 |
Parameter2 | 4 | UINT32 |
Parameter3 | 4 | UINT32 |
Parameter4 | 4 | UINT32 |
Parameter5 | 4 | UINT32 |
- Response Code:响应码 ,包含定义在 PTP 标准协议 第 11.1 和 11.3 [1]节 的操作响应码。
- TransactionID:事务 ID,它在连接到响应端设备的开放会话上下文中是唯一的,如 PTP 第 9.3.1[11]节中定义。TransactionID 是一个从 0x00000001 到 0xFFFFFFFE 的连续数值。0x00000000 作为特殊的值,只能被用于 OpenSession 或GetDeviceInfo两个操作请求,每次当此参数不适用于包时,必须使用另一个特殊值 0xFFFFFFFF。
- Parameter 1~5:这些字段包含特定于操作的参数,这些参数的解释取决于生成响应的操作以及特定的响应代码值。一个操作响应的数据包最多可以容纳 5 个参数。这些参数的使用方式定义在 PTP 标准协议的 9.3.4 [1] 节。
实际该数据包结构如下:
对应地:
- 0e 00 00 00:第 0~3 字节表示 Length 字段
- 07 00 00 00:第 4~7 字节表示 Packet Type 字段
- 01 20:第 8~9 字节表示 Response Code 字段
- 05 00 00 00:第 10~13 字节为 Transaction ID 字段
2.3.8 Event Packet
事件数据包 。该数据包用于传输在 PTP 标准协议12.2 [1] 节中定义的事件。这些事件由响应端设备通过事件连接通道发送给启动器设备,以通知启动器设备响应端的状态变更。
包结构如下:
Field | Size[Bytes] | Data Type |
---|---|---|
Length | 4 | UINT32 |
Packet Type | 4 | UINT32 |
Event Code | 2 | UINT16 |
TransactionID | 4 | UINT32 |
Parameter1 | 4 | UINT32 |
Parameter2 | 4 | UINT32 |
Parameter3 | 4 | UINT32 |
- Event Code:事件码 ,包含定义在 PTP 标准协议 第 12.3 和 12.4 [1]节 的事件码。
- TransactionID:事务 ID,它在当前连接到响应端设备的开放会话上下文中是唯一的,其定义在 PTP 标准协议的 9.3.1 [1] 节。如果事件数据包对应于先前发起的事务,则该字段应该被设为操作所对应的事务 ID。如果事件没有指定于特定的事务,则该字段应设为0xFFFFFFFF。
- Parameter 1~3:这些字段包含特定于事件的参数。这些参数的解释却决于 事件码 (Event Code) 字段。一个 Event Packet 数据包最多能容纳 3 个参数,有关这些参数的使用说明定义在 PTP 标准协议的 12.5 [1] 节。
2.3.9 Start Data Packet
开始数据传输数据包。该数据包在 PTP-IP 中用于标识数据传输的开始。其通过命令 / 数据通道传输,可以由任意一设备端发送,另一端接收。
包结构如下:
Field | Size[Bytes] | Data Type |
---|---|---|
Length | 4 | UINT32 |
Packet Type | 4 | UINT32 |
TransactionID | 4 | UINT32 |
Total Data Length | 8 | UINT64 |
- Total Data Length:包含即将在 数据读 (data in) 阶段或 数据写 (data out) 阶段中被传输的数据大小。特定的值 0xFFFFFFFFFFFFFFFF 表示在数据阶段的开始并不知道数据的大小,该值的使用仅限于传输对象的大小未知的情况(例如:传输流数据)。
数据包示例:
其中:
- 14 00 00 00:第 0~3 字节表示 Length 字段
- 09 00 00 00:第 4~7 字节表示 Packet Type 字段
- 01 00 00 00:第 8~11 字节表示 Transaction ID 字段
- 08 00 00 00 00 00 00 00:第 12~19 字节为 Total Data Length 字段
2.3.10 Data Packet
该数据包在 PTP-IP 中用于传输数据。Data Packet包只在数据阶段使用,且可以由当前数据流方向上的任意一端发送,另一端接收:在 数据读 (data-in) 阶段由响应端设备发送给启动器设备;在 数据写 (data-out) 阶段由启动器设备发送给响应端设备。Data Packet数据包走的是命令 / 数据的连接通道。
由于 TCP 传输是 无错误 、 基于流 的协议,通常不需要对大型的数据包进行拆包和粘包操作。不过可以使用基本的碎片机制来实现一个简单的数据传输取消机制,Data Packet不需要进行错误校验。
包结构如下:
Field | Size[Bytes] | Data Type |
---|---|---|
Length | 4 | UINT32 |
Packet Type | 4 | UINT32 |
TransactionID | 4 | UINT32 |
Data Payload | ? | UINT8 |
- Data Payload:包含数据包中需要传输的数据。
数据包示例:
其中:
- 14 00 00 00:第 0~3 字节表示 Length 字段
- 0a 00 00 00:第 4~7 字节表示 Packet Type 字段
- 01 00 00 00:第 8~11 字节表示 Transaction ID 字段
- 00 00 00 00 00 00 00 00 0c 00 00 00 0c 00 00 00 01 00 00 00 0e 00 00 00 07 00 00 00 01 20 01 00 00 00:第 12~N 字节为 Data Payload 字段。
2.3.11 End Data Packet
终结数据传输 的数据包。End Data Packet数据包在 PTP-IP 中用于标识数据阶段的结束,该数据包中也可以携带一些有用数据。该数据包只在一个事务的数据阶段使用,可以由数据流方向上的任意一端发送,另一端接收:在 数据读 (data-in) 阶段由响应端设备发送给启动器设备;在 数据写 (data-out) 阶段由启动器设备发送给响应端设备。
包结构如下:
Field | Size[Bytes] | Data Type |
---|---|---|
Length | 4 | UINT32 |
Packet Type | 4 | UINT32 |
TransactionID | 4 | UINT32 |
Data Payload | ? | UINT8 |
- Data Payload:如果数据包中包含有数据则放在这个字段。
数据包示例:
其中:
- 10 00 00 00:第 0~3 字节表示 Length 字段
- 0c 00 00 00:第 4~7 字节表示 Packet Type 字段
- 06 00 00 00:第 8~11 字节表示 Transaction ID 字段
- 02 00 01 00:第 12~(Length-4-4-4) 字节为 Data Payload 字段。
2.3.12 Cancel Packet
Cancel Packet数据包用于取消传输事务,由启动器设备发送至响应端设备。该数据包在命令 / 数据连接通道和事件连接通道上发送。
包结构如下:
Field | Size[Bytes] | Data Type |
---|---|---|
Length | 4 | UINT32 |
Packet Type | 4 | UINT32 |
TransactionID | 4 | UINT32 |
2.3.13 Probe Request Packet
心跳包 。该数据包可用于 PTP-IP 的启动器设备和响应端设备,以检查对等设备是否仍然有效。当接收到该数据包时,设备必须立即响应一个Probe Response Packet 数据包。如果在一段合理的时间内没有收到响应,则发出该数据包的设备将关闭与对端设备的 PTP-IP 会话。
包结构如下:
Field | Size[Bytes] | Data Type |
---|---|---|
Length | 4 | UINT32 |
Packet Type | 4 | UINT32 |
数据包示例:
其中前、后四个字节分别为 Length 字段和 Packet Type 字段。
使用该数据包时应要注意控制发送的频率以避免造成局域网过载:
- 启动器设备发送至响应端设备(I–>R):建议这个包只在 PTP 事务中使用(例如,当发出格式命令时,如果存储介质很大,响应时间可能会很长),以便检查响应端设备是否仍然处于活跃状态。
- 响应端设备发送至启动器设备(R–>I):建议仅当响应端设备接收到一个新的 PTP-IP 会话的请求,而另一个或多个其他会话处于活动状态时,才使用此包。在这种情况下,响应端设备可以检查现有的 PTP-IP 连接是否仍然处于活动状态。
- 建议在发送 Probe Request Packet 数据包和接收 Probe Response Packet 包之间设置 10 秒 的超时时间。
2.3.14 Probe Response Packet
心跳包的回应数据包。该数据包可用于 PTP-IP 的启动器设备和响应端设备,作为另一端的 Probe Request Packet 请求的响应。当接收到一个 Probe Request Packet 请求时应当立即回复这个数据包。
包结构如下:
Field | Size[Bytes] | Data Type |
---|---|---|
Length | 4 | UINT32 |
Packet Type | 4 | UINT32 |
数据包示例:
其中前、后四个字节分别为 Length 字段和 Packet Type 字段。
2.4 会话的实现
由启动器设备在 PTP 层发起的新会话请求将生成 两个 新的 TCP 连接,这两个连接即对应于 PTP-IP 层的 命令 / 数据 (Command/Data) 连接和 事件 (Event) 连接。这两个 TCP 连接足够用来唯一标识其所属的会话,因此不需要将 会话 ID(SessionID)作为独立的值从启动器设备发送到响应端设备。
2.5 设备断开和网络丢失处理
在 PTP-IP 协议中,对设备的断开或者网络丢失的检测基于以下一些标准:
- 网络层通知应用程序有关网络连接断开 (例如媒体断开连接) 的功能。
- 任意一个 PTP-IP 连接通道丢失(命令 / 数据通道或事件通道),例如 socket 被破坏。
- 任意一个 PTP-IP 通道传输超时。
2.6 数据流控制
为了防止一个设备在事务的数据阶段用数据重载另一个设备,通常会实现一个数据流控制机制。不过在 PTP-IP 中不需要实现这样的机制,因为底层的 TCP 层会执行流控制操作。
TCP 层在两个级别实现流控制:接收设备 和网络,避免在低速接收和低速网络下数据泛滥。因此,在 PTP-IP 中采用 TCP 连接作为通信通道,直接解决了流量控制的问题。
2.7 事务取消机制
有两种可能取消事务的情况:启动器设备请求取消或者响应端设备请求取消。
2.7.1 启动器设备产生的取消
2.7.1.1 数据写阶段
启动器设备为了取消正在进行的数据写阶段传输,必须在命令 / 数据通道和事件通道上发出一个 Cancel Packet 数据包,并停止任何正在命令 / 数据通道上的数据传输。当响应端设备在命令 / 数据通道或事件通道上收到 Cancel Packet 数据包时,必须尽可能快地中断并取消正在进行的事务,同时读取和丢弃所有属于当前事务 (如果有) 的剩余的数据包,并且向启动器设备回应一个附带有 Transaction_Cancelled 响应码的 Operation Response Packet 数据包。
2.7.1.2 数据读阶段
启动器设备为了取消正在进行的数据读阶段传输,必须在命令 / 数据通道和事件通道上发出一个 Cancel Packet 数据包。响应端设备在命令 / 数据通道或事件通道上收到 Cancel Packet 数据包时,必须尽可能快地中断并取消正在进行的事务,并且向启动器设备回应一个附带有 Transaction_Cancelled 响应码的 Operation Response Packet 数据包。
2.7.1.3 其他事务阶段
启动器设备可以通过在命令 / 数据通道和事件通道上发出一个 Cancel Packet 数据包以在事务的任意阶段退出事务。如果取消的是当前的事务,则响应端设备必须回应一个附带有 Transaction_Cancelled 响应码的 Operation Response Packet 数据包。
2.7.2 响应端设备产生的退出
2.7.2.1 数据写阶段
响应端设备为了取消正在进行的数据写阶段传输,必须发送一个附带有 Transaction_Cancelled 或者其他标识数据传输中断原因的响应码的 Operation Response Packet 数据包。然后,响应端设备必须读取和丢弃所有属于当前事务的在命令 / 数据通道中的 Data Packet 数据包。
2.7.2.2 数据读阶段
响应端设备为了取消正在进行的数据读阶段传输,必须在命令 / 数据通道上发送一个 Operation Response Packet 数据包,并且附带 Transaction_Cancelled 响应码或其他标识数据传输中断原因的响应码。
2.7.2.3 其他事务阶段
响应端设备可以通过发送附带 Transaction_Cancelled 响应码或其他标识数据传输中断原因的响应码的 Operation Response Packet 以在事务的任意阶段退出事务。
2.7.3 异步操作退出机制
启动器设备为了取消一个异步操作,必须同时在命令 / 数据通道和事件通道发送一个包含该异步操作所属的事务 ID 的 Cancel Packet 数据包,启动器设备可以在任意时候发送这些数据包。
响应端设备将以 PTP 事件 (例如 Capture Complete event) 结束操作。解释取消请求的逻辑由响应端设备的应用层负责。
3 协议版本
该 PTP-IP 规范的二进制协议版本 (BINARY PROTOCOL VERSION) 是 0x00010000(1.0 版)。二进制协议版本由一个主要数字 (高 16 位表示) 和一个次要数字 (低 16 位表示) 组成。这个数字将增加,以表示较新的协议版本,方法如下:
- 次要版本 进行了增加,以反映协议规范中的次要更改。实现新次要版本的设备必须完全支持同一主要版本的所有次要版本。
- 主要版本 增加了,以反映协议规范中的主要更改。新协议规范可能与主号码较小的旧规范版本不兼容。
4 PTP-IP 端口
如果没有实现设备发现协议,则每一个响应端设备和启动器设备应该通过以下端口号来初始化:
Port Name | Port No. | Type | Description |
---|---|---|---|
PTP-IP service | 15740 | TCP | 响应端设备等待 TCP 连接的默认端口,该端口由 IANA 批准。 |
5 附录
5.1 地址配置
PTP-IP 协议的基础是 TCP/IP 协议,该协议的关键是寻址机制。响应端设备和启动端程序都将获得有效的 IP 地址。获取有效 IP 地址的方法有以下几种:
- 手动配置:IP 地址和其他网络属性由用户手动配置,以反映图像设备将在其中工作的局域网的拓扑结构和地址模式;
- 基于 DHCP 配置:图像设备应实现一个 DHCP 客户端,DHCP 客户端将自动从网络中的 DHCP 服务器获取 IP 地址。
- IPv4 链路本地地址 (v4LL) 的动态配置:一个描述了一种在 TCP/IP 局域网上自动自配置网络设备的机制,而无需设置 DHCP 服务器的标准。
为了处理设备的 TCP/IP 属性配置,建议执行以下步骤:
- 如果属性是手动配置的,则使用该配置;
- 否则设备应使用 DHCP 协议获取 IP 地址以及其他配置参数(设备需要实现一个 DHCP 客户端);
- 如果网络中没有 DHCP 服务器,则可以部署 v4LL 动态配置。
5.2 设备发现和枚举
在 PTP-IP 中,启动器设备可以通过以下几种方式配置连接到响应端设备的地址:
- 手动配置:启动器设备将手动配置它可以连接的响应端设备的一个或一组地址。启动器设备会尝试根据 IP 地址建立一个 PTP-IP 连接,如果连接成功则说明响应端设备存在,此时可以建立一个 PTP 会话。
- Zeroconf:一族提供自动配置、设备和服务发现的协议和建议,在 IETF Zeroconf Working Group.[4] 中发表。
- UPnP:一组发表在 UPnP Forum[3] 用于简化设备配置、服务发现和调用的协议。仅可以使用该协议的设备和服务发现功能。
- 其他设备发现机制。
PTP 规范第 7.4 条要求从其传输中支持设备发现和枚举。因此,PTP-IP 层应该至少实现以上这些服务中的一种。
不管使用什么服务发现和枚举,我们建议将设备的 GUID 作为广播包的一部分,这样启动端设备就能够过滤 (如果需要的话) 特定的设备,并生成选择性通知。
5.3 设备绑定和认证
认证并不是 PTP-IP 层的职责。如果需要身份验证,则应该依赖于底层网络 (物理 / 数据链路层) 中可用的解决方案。设备绑定可以依赖于底层网络可用的机制或者基于 PTP-IP 层提供的机制在应用层实现,如下:
PTP-IP 上下文中每一个设备都需要由一个可被用于设备绑定的全局唯一的标识:GUID(16 字节的唯一数字)。对于这些设备,PTP-IP 层提供了一个允许启动器设备和响应端设备互相交换 GUID 的机制。这进而允许应用层实现设备级访问控制(例如,一个新设备到达并被网络发现,该设备只能接受来自已知启动器设备的的选择性连接,或者只能启动到已知响应端设备的连接)。
无论使用什么服务发现和枚举方法,都建议将设备的 GUID 作为广播包的一部分,这样启动端设备就能够过滤 (如果需要的话) 特定的设备,并生成选择性通知。
5.4 数据安全
本节不属于 PTP-IP 协议的范围。数据安全将依赖于底层网络 (物理 / 数据链路层) 中可用的解决方案。
5.5 The End :)