本文档描述了一个基于IP网络的ISO-15740/PIMA1574:2000/图片传输协议(PTP)的实现。
PTP被设计用来提供与数字静止摄影设备的标准通信。该协议指定了标准的图像引用行为、操作、响应、事件、设备属性、数据集和数据格式,以确保互操作性,还提供了可选的操作和格式,以及扩展机制。
Thekeywords“MUST”,“MUSTNOT”,“REQUIRED”,“SHALL”,“SHALLNOT”,“SHOULD”,“SHOULDNOT”,“RECOMMENDED”,“NOTRECOMMENDED”,“MAY”,“OPTIONAL”inthisdocumentaretobeinterpretedasdescribedin“KeywordsforuseinRFCstoIndicateRequirementLevels”[5].
下表列举了本文档的参考资料:
PTP规范定义了设备角色、操作、图像格式和其他相机特定的数据类型和结构。在PTP的TCP/IP实现中,所有术语和定义都按照PTP规范中定义的那样使用。
从通信的角度来看,设备可以充当启动器设备(Initiator)或响应端设备(Responder),启动器设备相当于一个客户端,响应端设备相当于服务端。启动器设备是向响应端设备发起操作请求的设备。响应端设备则是能够响应这些操作请求的设备。一个设备可能只是一个启动器设备,或者只是一个响应端设备,或者两者兼备,但不能在同一个设备连接上同时担任两种角色。
操作请求只能由启动器设备发起;事件被响应端设备用于把有关它状态的改变通知启动器设备。
根据PTP协议,会话被定义为两个设备之间的逻辑连接,操作和事件事务可以通过该逻辑连接进行通信。根据PTP规范,一个响应端设备可以支持多个并发会话,每个会话都有自己的状态。
当启动器设备请求OpenSession操作事务时将会打开一个会话,并且使用响应端设备发出的一个有效响应成功结束该请求。
会话将在启动器设备请求CloseSession操作事务时被关闭,并且使用响应端设备发出的一个有效响应成功结束该请求。当启动器设备和响应端设备之间的连接被关断开时会话也会被关闭(例如通信超时)。
大多数操作需要在一个开放会话上下文中执行。不过,不需要打开会话就可以通过GetDeviceInfo操作获取设备功能。
支持多会话的设备必须能够使它们彼此保持异步和不透明。
通常,如果使用相同传输级别的通信通道,则会话ID旨在使响应端设备能够按适当的顺序分发来自不同启动器设备的请求。对于打开不同通信通道的传输,对于每个会话,不需要重新设置会话ID,因为响应端设备将能够处理多个会话。
PTP的PTP-IP传输实现不会将会话ID发送到响应端设备。响应端设备可以通过控制它允许的最大PTP-IP连接数来限制并发PTP会话的数量。
如果启动器设备的PTP-IP层发现响应端设备不接受新的PTP-IP连接,它将向PTP层发送传输特定的错误代码。在建立传输指定连接之后,启动端设备可以向远程响应端设备发出GetDeviceInfo和OpenSession请求。在这个阶段中,响应端设备可能返回一个设备繁忙(Device_Busy)的PTP错误作为对OpenSession的响应(如果响应端设备对它能够支持的并发PTP会话的数量有限制)。在这种情况下,启动端设备应该释放PTP连接,并稍后重试。
一个事务通常由三个阶段组成:OperationRequest、OperationResponse、DataPhase,如下图:
取决于事务操作本身,DataPhase这一可选阶段可能不会存在于一个事务流程中,即事务只有OperationRequest和OperationResponse。而当事务中存在DataPhase时,数据可能从初始化器Initiator发送到响应设备Responder(即I–>R),或者反过来R–>I,但同一个操作中数据只能在一个方向上传输。
事务ID(TransactionID)用于在一个给定的会话中标识不同事务,与在PTP协议的第9.3.1项中定义的事务ID相同,是一个32位无符号整型数字。事务ID在给定的会话中是唯一且连续的数字序列,其范围从0x00000001到0xFFFFFFFE,0x00000000和0xFFFFFFFF作为保留值不被使用。
在PTP标准协议的7[1]节中,为底层传输层定义了这些需求。
在PTP-IP的实现中,用户程序与PTP-IP层之间的通信基于PTP事务模型实现,参考PTP协议的9.3[1]节,该通信模型如下图:
本文档的目的在于制定和说明PTP-IP通信协议,应用程序和PTP-IP层(编程接口,API)之间交互的实现并不在本文档的内容范围内。本文档仅以互操作性的方式规定两个PTP-IP实体之间的通信。不过,PTP层(用户应用程序)和PTP-IP层之间的接口可能由以下基本类型组成:
操作和事件两种事务的类型的定义在PTP协议文档的10.11、12[1]节中可以找到,并且PTP协议在14[1]节中为设备标准的一致性确定了一组操作和事件。
PTP标准协议文档的7[1]节定义了PTP标准传输需求,而PTP-IP则是基于使用TCP层作为传输层实现:
与PTP一样,PTP-IP也期望从其传输层获得可靠、稳定无错误的通信通道,而TCP(位于TCP/IP协议栈中)正是可以满足这些需求的自然传输层。TCP是一个基于流的传输层,它提供多个通信通道(TCPConnection)和无错误的数据传输。
在PTP-IP中,两个设备之间的所有通信都通过两个TCP连接(逻辑数据通道)进行:
由于事件本身具有异步性质,事件的数据包与操作/数据事务数据包分开分别通过两个单独的通道传输。
PTP-IP的命令/数据连接用于传输PTP操作请求、响应和数据事务,以及特定于PTP-IP的数据包。该连接由启动器设备(Initiator)建立,并标志本地及响应端设备(Responder)的IP地址和端口号。响应端设备(Responder)的IP地址和端口号通常是通过设备发现机制来确定。
PTP-IP的事件连接作为启动器设备(Initiator)开启的与响应端设备(Responder)之间的第二个连接,用于传输PTP事件,以及特定于PTP-IP的数据包。与命令/数据连接相同,事件连接由启动器设备(Initiator)发起建立,并标志本地和响应端设备(Responder)的IP地址和端口号,响应端设备(Responder)的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连接应遵循上图所示顺序进行:
根据PTP协议7[1]节,PTP-IP层要求传输通道可靠、无错误。这种传输通道可以通过正确配置TCP连接来实现。
PTP-IP的TCP连接应该使用一下选项创建:
总的来说就是需要设置如下选项(Qt为例):
//禁用Nable算法mTcpSocket->setSocketOption(QAbstractSocket::SocketOption::LowDelayOption,1);//开启KeepAlive选项mTcpSocket->setSocketOption(QAbstractSocket::SocketOption::KeepAliveOption,1);2.2.3.3关闭PTP-IP连接当不再需要PTP-IP时,由启动器设备(Initiator)关闭连接。当启动器设备(Initiator)或者响应端设备(Responder)在打开的传输通道上发生错误而导致这些通道不稳定时,也应关闭PTP-IP连接。关闭PTP-IP连接时两个TCP连接(命令/数据连接和事件连接)都必须要关闭。
本节主要介绍用于在启动器设备(Initiator)和响应端设备(Responder)间通信的一组数据包类型。PTP-IP的数据包类型相当于PTP协议中定义的操作请求(OperationRequest)、响应(Response)、数据(Data)和事件(Event)事务类型。PTP-IP数据包中的所有多字节值都使用小端(Little-Endian)格式表示,通常一个PTP-IP数据包的格式如下:
该数据包在命令/数据传输通道被建立后立即被启动器设备(Initiator)发送。该数据包通过命令/数据连接传输,用于通知响应端设备(Responder)对启动器进行标识,从而使响应端设备(Responder)能够实现过滤机制。数据包结构如下:
数据包示例:
对应地:
该数据包由响应端设备(Responder)回传给启动器设备,以响应启动器设备发送的InitCommandRequestPacket,并为接下来的PTP-IP会话分配一个连接号(ConnectionNumber),该数据包在命令/数据连接上传输。
包结构如下:
实际该数据包结构看起来如下:
命令/数据连接被成功建立后,该数据包被启动器设备发送至响应端设备用于建立事件连接。启动器设备在接收到一个有效的InitCommandAckPacket数据包后,立即建立事件的TCP连接并发送InitEventRequestPacket数据包,包中携带的连接号即前面步骤中接收到的在InitCommandAck数据包中返回的连接号。InitEventRequest数据包通过事件连接传输。
该数据包由响应端设备(Responder)通过事件连接通道回传给启动器设备,以告知启动器设备PTP-IP连接建立成功。
初始化失败数据包。当PTP-IP连接建立失败时,该数据包由响应端设备(Responder)回传给启动器设备,以告知启动器设备连接建立失败及失败原因,失败原因被记录在Reason字段。接收到该数据包之后,启动器设备必须关闭先前步骤中建立的命令/数据连接。该数据包发出后,响应端设备亦应关闭相应的PTP-IP连接(由启动器设备发起的被拒绝的TCP连接)。InitFailPacket可以通过任意的TCP连接传输。更多有关PTP-IP连接的建立可以参考PTP-IP连接一节内容。
Reason字段包含了连接拒绝的错误码,该字段定义的错误码有以下几种:
操作请求数据包。该数据包在PTP-IP协议中用于传输在PTP标准协议9.3.2[1]节定义的PTP操作请求。PTP-IPOperationRequestPacket由启动器设备发送至响应端设备,并通过命令/数据通道传输。
实际该数据包结构如下:
操作响应数据包。该数据包在PTP-IP协议中用于传输在PTP标准协议9.3.4[1]节定义的PTP操作响应。PTP-IPOperationResponsePacket数据包由响应端设备通过命令/数据通道回应给启动器设备。操作响应数据包仅在需要指示操作请求事务已经结束并且需要传递操作结果时才由响应端设备发送给启动器设备。
事件数据包。该数据包用于传输在PTP标准协议12.2[1]节中定义的事件。这些事件由响应端设备通过事件连接通道发送给启动器设备,以通知启动器设备响应端的状态变更。
开始数据传输数据包。该数据包在PTP-IP中用于标识数据传输的开始。其通过命令/数据通道传输,可以由任意一设备端发送,另一端接收。
其中:
该数据包在PTP-IP中用于传输数据。DataPacket包只在数据阶段使用,且可以由当前数据流方向上的任意一端发送,另一端接收:在数据读(data-in)阶段由响应端设备发送给启动器设备;在数据写(data-out)阶段由启动器设备发送给响应端设备。DataPacket数据包走的是命令/数据的连接通道。
由于TCP传输是无错误、基于流的协议,通常不需要对大型的数据包进行拆包和粘包操作。不过可以使用基本的碎片机制来实现一个简单的数据传输取消机制,DataPacket不需要进行错误校验。
终结数据传输的数据包。EndDataPacket数据包在PTP-IP中用于标识数据阶段的结束,该数据包中也可以携带一些有用数据。该数据包只在一个事务的数据阶段使用,可以由数据流方向上的任意一端发送,另一端接收:在数据读(data-in)阶段由响应端设备发送给启动器设备;在数据写(data-out)阶段由启动器设备发送给响应端设备。
CancelPacket数据包用于取消传输事务,由启动器设备发送至响应端设备。该数据包在命令/数据连接通道和事件连接通道上发送。
其中前、后四个字节分别为Length字段和PacketType字段。
使用该数据包时应要注意控制发送的频率以避免造成局域网过载:
心跳包的回应数据包。该数据包可用于PTP-IP的启动器设备和响应端设备,作为另一端的ProbeRequestPacket请求的响应。当接收到一个ProbeRequestPacket请求时应当立即回复这个数据包。
由启动器设备在PTP层发起的新会话请求将生成两个新的TCP连接,这两个连接即对应于PTP-IP层的命令/数据(Command/Data)连接和事件(Event)连接。这两个TCP连接足够用来唯一标识其所属的会话,因此不需要将会话ID(SessionID)作为独立的值从启动器设备发送到响应端设备。
在PTP-IP协议中,对设备的断开或者网络丢失的检测基于以下一些标准:
为了防止一个设备在事务的数据阶段用数据重载另一个设备,通常会实现一个数据流控制机制。不过在PTP-IP中不需要实现这样的机制,因为底层的TCP层会执行流控制操作。
TCP层在两个级别实现流控制:接收设备和网络,避免在低速接收和低速网络下数据泛滥。因此,在PTP-IP中采用TCP连接作为通信通道,直接解决了流量控制的问题。
有两种可能取消事务的情况:启动器设备请求取消或者响应端设备请求取消。
启动器设备为了取消正在进行的数据写阶段传输,必须在命令/数据通道和事件通道上发出一个CancelPacket数据包,并停止任何正在命令/数据通道上的数据传输。当响应端设备在命令/数据通道或事件通道上收到CancelPacket数据包时,必须尽可能快地中断并取消正在进行的事务,同时读取和丢弃所有属于当前事务(如果有)的剩余的数据包,并且向启动器设备回应一个附带有Transaction_Cancelled响应码的OperationResponsePacket数据包。
启动器设备为了取消正在进行的数据读阶段传输,必须在命令/数据通道和事件通道上发出一个CancelPacket数据包。响应端设备在命令/数据通道或事件通道上收到CancelPacket数据包时,必须尽可能快地中断并取消正在进行的事务,并且向启动器设备回应一个附带有Transaction_Cancelled响应码的OperationResponsePacket数据包。
启动器设备可以通过在命令/数据通道和事件通道上发出一个CancelPacket数据包以在事务的任意阶段退出事务。如果取消的是当前的事务,则响应端设备必须回应一个附带有Transaction_Cancelled响应码的OperationResponsePacket数据包。
响应端设备为了取消正在进行的数据写阶段传输,必须发送一个附带有Transaction_Cancelled或者其他标识数据传输中断原因的响应码的OperationResponsePacket数据包。然后,响应端设备必须读取和丢弃所有属于当前事务的在命令/数据通道中的DataPacket数据包。
响应端设备为了取消正在进行的数据读阶段传输,必须在命令/数据通道上发送一个OperationResponsePacket数据包,并且附带Transaction_Cancelled响应码或其他标识数据传输中断原因的响应码。
响应端设备可以通过发送附带Transaction_Cancelled响应码或其他标识数据传输中断原因的响应码的OperationResponsePacket以在事务的任意阶段退出事务。
启动器设备为了取消一个异步操作,必须同时在命令/数据通道和事件通道发送一个包含该异步操作所属的事务ID的CancelPacket数据包,启动器设备可以在任意时候发送这些数据包。
响应端设备将以PTP事件(例如CaptureCompleteevent)结束操作。解释取消请求的逻辑由响应端设备的应用层负责。
该PTP-IP规范的二进制协议版本(BINARYPROTOCOLVERSION)是0x00010000(1.0版)。二进制协议版本由一个主要数字(高16位表示)和一个次要数字(低16位表示)组成。这个数字将增加,以表示较新的协议版本,方法如下:
如果没有实现设备发现协议,则每一个响应端设备和启动器设备应该通过以下端口号来初始化:
PTP-IP协议的基础是TCP/IP协议,该协议的关键是寻址机制。响应端设备和启动端程序都将获得有效的IP地址。获取有效IP地址的方法有以下几种:
为了处理设备的TCP/IP属性配置,建议执行以下步骤:
在PTP-IP中,启动器设备可以通过以下几种方式配置连接到响应端设备的地址:
PTP规范第7.4条要求从其传输中支持设备发现和枚举。因此,PTP-IP层应该至少实现以上这些服务中的一种。
不管使用什么服务发现和枚举,我们建议将设备的GUID作为广播包的一部分,这样启动端设备就能够过滤(如果需要的话)特定的设备,并生成选择性通知。
认证并不是PTP-IP层的职责。如果需要身份验证,则应该依赖于底层网络(物理/数据链路层)中可用的解决方案。设备绑定可以依赖于底层网络可用的机制或者基于PTP-IP层提供的机制在应用层实现,如下:
PTP-IP上下文中每一个设备都需要由一个可被用于设备绑定的全局唯一的标识:GUID(16字节的唯一数字)。对于这些设备,PTP-IP层提供了一个允许启动器设备和响应端设备互相交换GUID的机制。这进而允许应用层实现设备级访问控制(例如,一个新设备到达并被网络发现,该设备只能接受来自已知启动器设备的的选择性连接,或者只能启动到已知响应端设备的连接)。
无论使用什么服务发现和枚举方法,都建议将设备的GUID作为广播包的一部分,这样启动端设备就能够过滤(如果需要的话)特定的设备,并生成选择性通知。
本节不属于PTP-IP协议的范围。数据安全将依赖于底层网络(物理/数据链路层)中可用的解决方案。