背景技术 许多诸如SMB(服务器信息块)协议的如今依然在使用的数据通信协议是在计 算资源非常不同的时期所开发的,例如,那时网络带宽通常是有限的并且存储器非 常珍贵。结果,当在当代网络中使用时,这样的协议可能限制总体性能。例如,由 于是在存储器有限的情况下设计的,所以使用了小的缓冲器大小,以致需要更多的 往返行程以传递大量数据。 此外,现有的SMB协议具有随着时间而变得明显的其他限制。例如,现有的 SMB协议容易受到服务拒绝攻击;协议的设计使其难于对抗这些攻击。同样地,确 保分组安全的方法是麻烦的。并且,当前没有用于执行类似服务质量的操作的机制, 因为例如受信任的客户端获得与不被信任的客户端相同的服务器资源。 虽然SMB协议的各种修订版或方言(dialect)已经随着时间而被开发,但是 那些方言中的每个方言实质上是基于补丁的方式,该方式调节多个部分以添加某些 额外的特征。如此,可扩展性不直接。总而言之,尽管现有的SMB修订版依然是经 常使用的以及有价值的协议,但当与当代网络资源结合使用时是较不理想的。 发明内容 简而言之,本发明的各种方面针对数据通信协议,客户端和服务器使用该数 据通信协议用于诸如文件共享之类的通信。客户端发送标识一组客户端理解的协议 方言的协商分组至服务器。分组以一种格式存在以使在不要求另一请求的情况下, 不能通过第二数据通信协议通信的服务器可表明应该使用第一通信协议。如果服务 器能够通过第二数据通信协议通信,那么它将这样回应。客户端将调用通过由服务 器表明的相应协议处理与服务器通信的驱动。在一示例实现中,第二通信协议是 SMB 2.0或更高级的版本。 协议的其他方面和增强可包括具有附加的其他上下文数据的创建命令,以及 包括多个相关命令或无关命令的复合命令。还有其他方面和增强包括涉及请求在独 立数据信道上的数据传送的多信道命令、确保安全连接被建立的签名能力验证请 求、以及响应于请求从服务器传送扩展的错误数据的能力。 当服务器接收到复合请求时,服务器确定该复合请求是否包括无关命令或相 关命令。当复合请求包括无关命令时,每个请求被处理成单独请求,否则,当复合 请求包括相关命令时,每个请求被顺序地处理。当相关命令包括创建/打开命令时, 来自创建/打开命令的文件处理被用于在服务器上的每个后续的相关命令,例如, 不需要等待来自客户端的处理返回。 其他优点将从以下结合附图的详细的描述中变得明显。 附图说明 本发明仅作为例子而被说明,不被附图所限制,其中相同的编号表明相同的 元素,其中: 图1显示了本发明的各方面可结合于其中的一般计算环境的示例性例子。 图2是表示了根据本发明的各方面的、客户端和服务器可在其中进行通信的 示例网络环境。 图3是一表示根据本发明的各方面的在客户端和服务器之间的示例协商和会 话建立的时序图。 图4是表示根据本发明的各方面的、包括具有创建上下文的创建命令的各种 命令的时序图。 图5是表示根据本发明的各方面的、在客户端和服务器之间的复合请求和可 能的响应的时序图。 图6是根据本发明的各方面、在多信道上客户端-服务器通信的表示。 图7是根据本发明的各方面的安全连接的验证的表示。 图8是根据本发明的各方面的、使用基于符号连接的例子的扩展的错误返回 信息的表示。 具体实施方式 示例性操作环境 图1示出了可在其中实现本发明的一合适的计算系统环境100的示例。计算 系统环境100只是一合适的计算环境的一例,而不是要提出对本发明使用或功能 的范围进行限制。计算系统环境100也不应解释成对于在示例计算系统环境100 中所示出的任一组件或其组合有任何依赖或需求。 本发明用多个其它通用或专用计算系统环境或配置是可运行的。可以适用于 本发明使用的公知的计算系统、环境、和/或配置的实例包括,但不局限于,个人 计算机、服务器计算机、手持设备或膝上型设备、平板设备、多处理器系统、 基于微处理器的系统、机顶盒、可编程消费电子产品、网络PC、小型机、大型 计算机、包括任何诸如以上系统或设备的分布计算环境等、诸如打印服务器或 打印机本身的各种网络应用设备中的一个、以及NAS存储设备等。 本发明可以在诸如由计算机执行的程序模块的计算机可执行指令的一般 上下文中被描述。一般地,程序模块包括完成特定任务或执行特定抽象数据类 型的例行程序、程序、对象、组件、数据结构等。本发明也可以在分布式计算 环境中实践,其中通过连接到计算网络的远程处理设备来执行任务。在分布式 计算环境中,程序模块可以位于包括存储器存储设备的本地和/或远程计算机 存储介质中。 参见图1,用于实现本发明的示例系统包括采用计算机110形式的通用计 算设备。计算机110的组件可包括,但不局限于,处理单元120、系统存储器 130、以及将包括系统存储器在内的各种系统元件耦合至处理单元120的系统 总线121。上述系统总线121可以是多种总线体系结构类型中的任何一种,包 括存储器总线或存储器控制器、外围总线和使用各种总线体系结构的任一种的 局部总线。举例来说,而非限制,此类体系结构包括工业标准体系结构(ISA) 总线、微通道体系结构(MCA)总线、增强型工业标准体系结构(EISA)总线、 视频电子标准技术协会(VESA)局部总线、和也被称为Mezzanine总线的外围 部件互连(PCI)总线。 计算机110通常包括各种计算机可读介质。计算机可读介质可以是任何计算 机110能够访问的可用介质,包括易失性的和非易失性的介质、可移动的和不 可移动的介质。举例来说,而非限制,计算机可读介质可以包含计算机存储介 质和通信介质。计算机存储介质包括能以任何方法或技术实现的易失性的和非 易失性的、可移动的和不可移动的介质,用于存储诸如计算机可读指令、数据 结构、程序模块或其它数据等信息。计算机存储介质包括,但不局限于,RAM、 ROM、EEPROM、闪存或其它存储技术,CD-ROM、数字多功能盘(DVD)或其它 光盘存储、盒式磁带、磁带、磁盘存储器或其它磁存储设备,或任何其它可以 被用来存储想要的信息并且可以被计算机110访问的介质。通信介质通常在诸 如载波或其它传送机制的已调数据信号中收录计算机可读指令、数据结构、程 序模块或其它数据,也包括任何信息传递介质。术语“已调制数据信号”是指 在该信号中以编码信息的方式来设置或改变其一个或多个特征的信号。举例来 说,而非限制,通信介质包括诸如有线网或直接线缆连接的有线介质,和诸如 声音、射频、红外线和其它无线介质的无线介质。任何以上所述的组合也可以 包括在计算机可读介质的范围之内。 系统存储器130包括以诸如只读存储器(ROM)131和随机存取存储器(RAM) 132的易失性和/或非易失性存储器的形式的计算机存储介质。包含如在启动期 间帮助在计算机110内各元件之间传送信息的基本例行程序的基本输入输出系 统(BIOS)133,通常存储在ROM 131中。RAM 132通常包含可以被处理单元 120立即访问和/或当前操作的数据和/或程序模块。举例来说,而非限制,图 1示出了操作系统134、应用程序135、其它程序模块136和程序数据137。 计算机110还可以包括其它可移动/不可移动、易失性/非易失性的计算机 存储介质。仅作为示例,图1示出了从不可移动、非易失性磁性介质读出或写 入不可移动、非易失性磁性介质的硬盘驱动器141、从可移动、非易失性磁性 磁盘152读出或写入可移动、非易失性磁性磁盘152的磁盘驱动器151、以及 从诸如CD ROM或其它光学介质的可移动、非易失性光盘156读出或写入可移 动、非易失性光盘156的光盘驱动器155。其它可以使用在示例的操作环境中 的可移动/不可移动、易失性/非易失性计算机存储介质包括,但不局限于,盒 式磁带、闪存卡、数字多功能盘、数字视频带、固态RAM、固态ROM、等。硬 盘驱动141通常通过诸如接口140的不可移动存储接口连接到系统总线121, 磁盘驱动151和光盘驱动155通常通过诸如接口150的可移动存储接口连接到 系统总线121。 以上讨论并且在图1中示出的驱动器及其它们相关的计算存储介质为计算 机110提供了计算机可读指令、数据结构、程序模块和其它数据的存储。在图 1,例如,示出硬盘驱动141存储操作系统144、应用程序145、其它程序模块 146、和程序数据147。需要注意的是这些组件可以和操作系统134、应用程序 135、其它程序模块136和程序数据137相同,也可以和它们不同。在此对操 作系统144、应用程序145、其它程序模块146和程序数据147给出了不同的 标号来说明至少它们是不同的副本。用户可以通过诸如写字板、或电子数字转 换器164、麦克风163、键盘162和定位设备161把指令和信息输入到计算机 110中,定位设备161通常如鼠标、轨迹球或触摸板。其它输入设备(图1中 未示)可以包括操纵杆、游戏垫、圆盘式卫星天线、扫描仪等等。这些和其它 输入设备通常由用户输入接口160连接到处理单元120,上述输入接口160和 系统总线121相耦合。但是上述和其它输入设备也可以由其它接口和总线结构 连接到处理单元120,诸如,并行端口、游戏端口或通用串行总线(USB)。监 视器191或其它类型显示设备也可以通过诸如视频接口190的接口连接到系统 总线121。监视器191也可以和触摸屏等集成在一起。需要注意的是监视器和/ 或触摸屏可以物理地耦合到包含了计算机110的一外壳,诸如写字板式个人计 算机。另外,诸如计算机110的计算机也可包括其它外围输出设备,诸如可以 通过一输出外围设备接口194等连接的扬声器195和打印机196。 计算机110可以在网络化的环境中运行,该环境使用逻辑连接连接到一个 或多个诸如远程计算机180的远程计算机。远程计算机180可以是个人计算机、 服务器、路由器、网络个人计算机、对等设备或其它公共网络节点,通常包括 以上描述的和110相关的多个或全部组件,尽管在图1中只示出了存储器存储 设备181。在图1中描绘的逻辑连接包括局域网(LAN)171和广域网(WAN) 173,但是也可以包括其它网络。这样的网络环境在办公室、企业范围的计算 机网络、内联网和因特网中是普遍的。 当在LAN网络环境中使用时,计算机110通过网络接口或适配器170连接 到LAN 171。当在WAN网络环境中使用时,计算机110通常包括调制解调器172 或通过诸如因特网的WAN 173建立通信的其他装置。调制解调器172可以是内 置的或外置的,可以通过用户输入接口160或其它适当的机制连接到系统总线 121。在一网络连接的环境中,所描述的和计算机110相关的程序模块或其中 的一部分可以存储在远程存储器存储设备内。举例说明,但非限制,图1示出 了驻留在存储设备181上的远程应用程序185。可以理解的是所示的网络连接 是示例的,也可以使用在计算机间建立通信链路的其他手段。 数据通信协议 在此描述的技术的各方面针对诸如SMB协议的较新版本(2.0或以上)的 数据通信协议。在此一般描述的一个示例实现中,SMB协议被用于文件数据传 送。然而,如可被容易理解的那样,本发明不局限于文件数据,也不局限于在 此描述的任何具体实现或示例。相反,各种实现本发明的方式都是可行的,包 括用于与打印机、指定的数据管道、类属设备等的通信。如此,本发明不局限 于在此使用的任何具体的基于文件的示例,而是可以一般在计算中提供益处和 优点的多种方式被使用。 在此描述的技术的其他各种方面针对SMB的新修订版,文件-服务器交互 可基于此SMB的新修订版而构建。如可被理解的那样,提供了一种支持现有(高 级)功能的更轻型的协议,并且该协议也更可扩展和更容易用新特征来更新。 转到图2,显示了表示一个示例网络环境的框图,在该网络环境中客户端 202与服务器204通过一个或多个通信信道通信。尽管客户端202和服务器204 的功能和组件被描述成位于两个单独的计算机内,诸如图1的主计算机系统100 和远程计算机系统180,但这两个计算机的组件或它们执行的功能可在一个机 器上被提供、或可被分布在多个计算机上。 来自应用程序206的网络文件系统命令由客户端重定向器组件208处理, 该客户端重定向器组件208与对应的公共网络模块(SRVNET)210通信,以在 文件系统212上执行命令。在这样的命令被处理之前,协商客户端和服务器同 意的通信协议,一般是双方都理解的最新的版本/方言。 一般地,如图3所一般表示的那样,客户端202建立连接并随后与服务器 204协商以最终建立会话。尽管客户端可直接对服务器表明其是SMB 2.X客户 端,(其中如在此使用的,数字2.X表示相对于现有SMB 1.X版本的任何较新 的版本),客户端也可通过向后兼容协商分组协商。通过这种方式,客户端也 能与只具有SMB 1.X能力的服务器通信,并且是不需要当较高级协商尝试失败 的情况下建立单独连接的。与此同时,用于实现每个协议的代码可被封装至它 自己的独立的驱动中。 在一示例实现中,客户端SMB引擎组件220提供分组至服务器(例如,服 务器204),该分组表明客户端202正在协商至少是SMB 1.0会话。对于既说 SMB1方言又说协议新的SMB2修订版的客户端202,客户端可发送传统的SMB1 协商分组,但是该分组还包括表明该分组实际上请求SMB 2.X(如果可行的话) 的指示。具有SMB2能力的服务器将检测到该请求,并以SMB2协商响应来响应。 更具体地,为了表明客户端202具有SMB 2.X的能力,SMB 1.0协商分组包括 一组方言串,这些串中的一个表明客户端也具有SMB 2.X通信的能力。 如此,客户端202发送包括客户端202支持的较小的修订版号的初始协商。 一个当前的修订版是0,即SMB 2.0;今后,客户端可要求支持方言修订版的 任何子集。 当服务器204接收分组时,服务器将基于它的能力做出响应。服务器204 可以SMB 1.0协商响应做出回应,并带有任何1.X方言信息,或者如果服务器 有SMB 2.X通信的能力,那么它将以SMB 2.0协商响应做出响应。具体的SMB 方言修订版也可被返回,该SMB方言修订版匹配方言串中的一个,一般是在客 户端202提供的方言版本中服务器204可处理的最大号的版本。 为此,一旦服务器204知道客户端202说的是哪些方言修订版,那么它把 这些与服务器204理解的修订版进行比较,并返回较佳的公共方言修订版(通 常是最高的)。例如,如果服务器支持方言1-8,但是客户端只支持1、2、和 4,那么服务器将返回4。这提供给客户端202有关它能发送哪个命令到服务器 204的清楚的理解。为了选择使用哪个方言,SRVNET模块210实质上开始协商, 把分组以相对于版本/方言从最高至最低的顺序传送至它所具有的每个SMB提 供器2221-222m,直到一个SMB提供器同意基于分组内容处理该通信会话为止。 此后,在该连接上的通信被传递至那个提供器,在此示例中是SMB 2.0提供器 222m。 在客户端处,SMB引擎组件220接收响应,并基于响应中的版本/方言信息 知道使用哪个客户端SMB组件2241-224n用于与服务器通信。通过这种方式,客 户端202和服务器204商定对于给定的会话使用哪个SMB方言。需要注意的是 客户端可具有多个同时运行的SMB组件2241-224n,每个组件是不同的版本/方 言,由此例如客户端可通过SMB 1.X与一个服务器通信,而同时该客户端可通 过SMB 2.X与另一个服务器通信。 服务器204也返回其他信息给客户端,包括告诉客户端202服务器204是 否要求安全签名的安全模式。注意,先前的安全签名是可用的,然而首批少量 的(例如,能力协商)分组畅行无阻,由此攻击者可能迫使一客户端进入较低 级协议,而攻击者知道该较低级协议中的弱点。 安全连接通过向另一方提供签名的能力验证往返行程来操作(不管签名是 否是可用的或不可用的)。图7显示了这样的请求/响应随动会话设置。其他 诸如IP地址的信息可被放到分组内以使服务器实际上可验证是它而不是另一 实体作出了响应。如果IPSEC或任何其他形式的网络安全是活动的,那么签名 可被关闭。 服务器204可返回服务器的能力位,例如,服务器是否明白DFS(分布式文 件系统),以及它是否能够LWIO(轻型IO)。客户端202不处理它不理解的任 何能力位,如果服务器204具有比客户端的相应版本更新的版本,这就可能发 生。可在协商交换中被返回的其它信息包括服务器的唯一ID、服务器可接受的 最大读/写大小、用于更快写操作的数据偏移量提示、服务器的当前系统时间、 以及用于在扩展的安全性的情况下的种子鉴别(seed authentication)的安 全信息。 会话设置处理新会话的鉴别过程,该过程可以是多往返行程事件。客户端 202查询本地安全系统关于安全块(security blob)以通过网络发送,以及发 送第一会话设置,填写了能力、最大大小字段、和以下描述的VcNumber。服务 器204接收该块并把它给予安全系统。如果服务器204确定需要更多的信息, 那么它将返回它自己的具有错误代码STATUS_MORE_PROCESSING_REQUIRED的安 全块。客户端202把该块发送回上述本地安全系统,并且该过程重复直到失败 发生或鉴别成功为止。 VcNumber告诉服务器204是否存在从该相同的客户端202建立的其它连接。 如果VcNumber是0,那么服务器204就假设没有从该客户端建立其它连接,并 且将拆毁它所发现的任何这样的连接(假设它们是失效的)。如果VcNumber 是1或更大,那么服务器204将不拆除任何现有的连接。 信道(Channel)告诉服务器204该客户端202正试图与现有的会话建立另一 连接。会话可由用户/计算机对来识别,该会话设置是从该用户/计算机对被接 收的。信道共享相同的TreeId/UserId/ProcessId/FileID信息。对于信道鉴 别,鉴别块可以是询问—响应,该询问—响应在第一信道上被加密,并且通过 第二信道被返回,以允许客户端202和服务器204之间相互地鉴证。在成功响 应后,服务器204还会通知该客户端202它是否已经被鉴别为Guest(客人)或 Null(空)用户,或被鉴别为其中的任何一个。 一旦会话被建立,那么客户端202可使用以下描述的包括创建、读、写和 关闭的各种命令来执行数据传送,以及执行文件锁定和目录相关的操作。如在 以上提到的“利用顺序号的数据通信协调”的专利申请中描述的那样,当使用 这些命令时,服务器能控制客户端对服务器资源的使用。并且,协议提供许多 关于什么信息被传递以及它如何被传递的有效改进。 如在图4中一般化地表示的那样,创建命令已经被扩展成允许上下文信息 被附加到命令上;一般地,上下文信息包括标记于创建命令的任意的额外创建 参数。例如,用于关于事务文件系统的创建命令的事务标识符可被附加。只要 服务器理解该额外的上下文信息,服务器就能被告知扩展的信息,(需要注意 的是服务器将忽略它们不理解的额外数据),并返回与上下文关联的信息。如 可被容易地理解的那样,这在不更改协议的情况下提供了额外的功能,实质上 提供了内置的可扩展性。 命令ID和方言修订版号被在以下描述的新的SMB头部所提供。与UCHAR相 比,头部具有用于命令字段的USHORT;通过使用该USHORT的第一字节表示方 言、以及使用较后的字节表示命令,对于现有的命令明确定义了命令表,很大 一部分可用于以后扩展。一般地,客户端可对每个方言维护一张表,该表包含 对发出给定命令的功能的指针。对于具有支持的单个方言的客户端,表如以下 被描述: 命令 方言#1 创建 SmbCreate1 读 SmbRead1 写 SmbWrite1 关闭 SmbClose1 为了高速缓存功能,更多的信息可在Close(关闭)时从文件中被检索。如此, 新的关闭命令被提供以支持该新的功能。现在客户端支持两种方言,表如以下所描 述: 命令 方言#2 方言#1 创建 SmbCreate1 SmbCreate1 读 SmbRead1 SmbRead1 写 SmbWrite1 SmbWrite1 关闭 SmbClose2 SmbClose1 需要注意的是大部分功能保持相同,除了更改的关闭命令。并且,客户端 现在能与方言2服务器通话并且使用新的功能,但是对于方言1服务器而言, 它依然使用旧的功能。对于与方言1服务器的通信没有更改。 随着技术的发展,新的诸如能执行相对更多读和写的网络硬件变得可用。 为了该版本,方言#3被提供,由此表被扩展成如下: 命令 方言#3 方言#2 方言#1 创建 SmbCreate1 SmbCreate1 SmbCreate1 读 SmbRead3 SmbRead1 SmbRead1 写 SmbWrite3 SmbWrite1 SmbWrite1 关闭 SmbClose2 SmbClose2 SmbClose1 具有这样的表的客户端能讲三种方言,并且将利用每个方言中可用的功能。 使用该方法的某些优点包括:由于命令由(方言|命令)组成,每个SMB命令 可被映射回它被引入的方言。这使得确定命令何时被引入以及什么服务器支持 它们变得容易。如果给定的命令的功能在新的方言中没有更改,那么代码不更 改。如果功能被更改,那么下级接口代码不更改,而新的代码被添加以支持新 功能。 在服务器方,服务器分派表变成在(方言)和(命令)之间的双切换。这 允许在代码内逻辑地分离新的功能,使得它更容易被理解和更改。 转到提供效率的协议的一个方面,多个命令可被复合成单个分组(或某些 较少数量的分组)。由此,复杂任务可通过减少在客户端202和服务器204之 间往返次数的方式被执行。作为例子,复合请求分组可包含创建/打开文件的 命令、写文件的命令以及读文件的命令。由此,复合对相关操作(例如,具有 相同文件句柄)起作用,并也为要被结合的无关操作做准备。 复合相关请求的例子被一般地表示在图5中,其中(例如,与图4相对比) 单个请求能处理读和写,只要提供适当的参数。需要注意的是如图5中所表示 的那样,单个请求可接收复合响应和/或个体响应,这取决于例如它们何时完 成。诸如创建/打开、读、写和关闭之类的更复杂的请求可在单个请求内。这 可通过把分组标记为具有相关操作来实现;服务器将知道它在创建/打开之后 接收的文件句柄适用于复合请求内的其他命令。然而,需要注意的是,相关复 合请求以它们被封装的顺序被处理,并且从而客户端负责在发送之前确保它们 被正确地排序。 SMB2中的复合比存在于SMB1中的复杂规则更为简单。为此,SMB2_HEADER (以下详细描述)包含用于标识下一命令头部离当前命令的头部的偏移量的 “NextOffset”。每个命令具有它自己的包括单独MessageId的SMB2_HEADER。 如图5所表示的,一个服务器响应或多个服务器响应可以是单个复合的响应或 是单独的响应。在失败事件中,响应与任何其他失败的命令相同。 对于无关消息,命令总是被处理好像它们被单独地接收那样。这允许重定 向器或中间组件自动地复合无关分组。延迟可被用于获取分组以复合,尤其是 在延迟时间相对于往返时间要小的情况下。由于服务器处将它们作为单独地被 接收,服务器不需要被另外修改以解包这种复合无关请求。然而,由于服务器 可结合另外的单独响应,执行复合的实体可能必须分离任何复合响应。 相关模式允许客户端发送要被依次执行的一系列命令,其中一个命令的结 果可能用于下一个命令。这样的命令共享相同的会话/过程/树/文件ID,它们 将被依次执行并在第一个错误处停止处理。如果在失败后有其他命令要处理, 那么操作立即失败,并具有STATUS_NOT_PROCESSED。这如何被使用的例子是把 会话设置(Session Setup)与树形连接(Tree Contact)配对。如果会话未 能被建立,那么树形连接将永不被尝试并且将失效并具有 STATUS_NOT_PROCESSED。如果会话设置成功,那么通过使用来自会话设置命令 的SessionId,树形连接被完成。相同的方法可被用以执行在 QueryFileInformation之后的创建(Create),或甚至是创建-读-关闭 (Create-Read-Close)组。 有条件的以及隐含的复合也是可行的。例如,有条件的复合命令可被发送,诸 如如果文件小于64KB,那么打开以及读文件,从而在一次往返中打开和自动获取 小的文件,但仅仅打开大的文件。隐含的复合,诸如响应于打开目录请求,即使没 有明显地请求也自动地返回目录枚举数据,,这也能减少往返次数。对于这种增强 的复合的益处和优点在高等待时间网络中增加。 协议促进提高的效率的另一种方式是通过多信道通信。在客户端和服务器之 间,命令的传送连接可结合指定备选信道来流式传输数据的命令而被使用。例如, 读请求可指定偏移量和长度以及数据可被读至的备选信道;写请求类似地操作。图 6显示了1GB读请求的例子,该读请求从偏移量为0处开始并请求数据被流式传输 到数据信道5。 在备选信道上流式传输数据提供了多个益处,包括消除对包括和处理分组头部 的需要。客户端可预先公布缓冲器并使数据流入其中,消除对如在传统单信道通信 中的从一个缓冲器备份到另一缓冲器的需要。公平性是另一个益处,因为例如控制 信道上的一个请求将不需要在其他请求被处理之前等待大量数据(例如,5GB)以 完成被传送,因为5GB将通过数据信道。 随着多NIC变得越来越普遍,协议利用任何可用的网络带宽。这包括对于相同 会话跨多个连接进行工作,而不管它们被建立于其上的传送(或NIC)。专用硬件 可被使用。 如此,通过使用SMB 2.X,会话不必局限于一个连接。相反,多个跨不同的物 理连接而存在的“信道”可被建立。会话可在这些连接中的每个连接上存在,并且 被用以参考文件和过程的ID在信道之间是公共的。这允许使常规信道进行名字空 间操作和创建,而使用专用网络硬件进行读和写(当可用时)。更进一步,由于只 要有一个信道对会话保持开放,会话就保持有效,所以小的网络故障不导致丢失数 据。各种实现细节在此参考会话设置命令和读/写命令而被描述。 作为例子,考虑通过简单TCP在企业的公共网上建立对服务器的连接的客户端。 这是第一连接,所以总是信道0。一旦双方检测到它们具有用于数据传送的专用网 (例如,每方都具有千兆位卡),客户端和服务器可通过该卡建立第二连接,如信 道1。当客户端浏览某些文件时,目录查询通过信道0被发送,而数据通过信道1 被发送。如果客户端要在服务器上被加密的某些目录中浏览,当客户端请求数据时, 重定向器识别出数据是敏感的,所以它建立对服务器的新的信道(信道2),该信 道上具有活动的IP Sec(IP安全性)。当客户端请求敏感数据时,它将要求数据通 过信道2被发送,而正常的较不敏感的数据继续通过信道1(由于这比较快)到来。 如可被容易理解的那样,QoS和安全性改进的机会与简单带宽增益一起提供显 著的益处。需要注意的是在信道读/写上,服务器/客户端可在任何数据被读之前拟 定接收缓冲器,所以该机制可进一步消除对将数据移动备份出来的需要,这也能提 高服务器/客户端的可扩展性。 此外,SMB错误分组被允许用任意数据来标记。因此,关于为何某些过程失败 的描述可提供值。符号连接评估是一个例子,如在图8中一般地表示的那样,其中 用任意数据标记向客户端提供了有用的信息。实质上,客户端创建请求可通过请求 实质上是对于另一路径的符号连接的路径而失败。不是简单地使请求失败,而是提 供新路径的信息允许客户端更改到将最终成功的重新解析路径;需要注意的是可能 需要多个请求的反复以寻找会成功的路径。 示例协议定义 新头部是64字节结构(例如,一个当前结构的两倍大小)。 typedef struct_SMB2_HEADER{ UCHAR Protocol[4]; //包含OxFE,′S′,′M′,′B′ USHORT StructureSize; //=sizeof(SMB2_HEADER). //(版本化) USHORT Epoch; //每次服务器重新启动时递增 NTSTATUS Status; //命令的状态 USHORT Command; //用于这个分组联合的命令 { USHORT CreditsRequested; //在客户端发送时,请求更多的信用 USHORT CreditsGranted; //在服务器响应时,信用被授予给客户端 }; ULONG Flags; ULONG Reserved; UINT64 MessageId; //标识该消息发送/响应 //发送/响应 union { struct { UINT64 ProcessId; //过程标识符 UINT64 SessionId; //会话标识符 ULONG TreeId; //树形连接标识符 }; struct { UINT64 AsyncId; //用于标识长期命令 }; }; UCHAR Signature[8]; //分组的签名 ULONG NextCommand; //到下一个命令的偏移量 }_SMB2_HEADER,*PSMB2HEADER; Protocol只是协议标识符,以识别分组。对于现有的SMB实现,这包括{OxFF, ‘S’,‘M’,‘B’}。对于新的协议,这应该是{OxFE,‘S’,‘M’,‘B’}。 StructureSize标识SMB2_HEADER结构的大小,如果稍候引入其他更改,则将 被用于头部(Header)本身内的较小的版本化。 Epoch表示服务器的“版本计数”。当服务器被循环(或服务器服务被终止以及 开始)时,Epoch被递增以对客户端表明服务器是否可能已经保存了断开连接时的 状态。这是用于将来持续处理并能被考虑成对于时间“预留的”。 Status给出如在现有的SMB实现中的对于给定操作的错误状态。 Command标识如在此描述的分组的命令。 CreditsGranted/CreditsRequested由客户端在发送时使用以请求更多的信用,以 及由服务器在响应时使用以在新的信用管理方案内授予更多信用,如在相关的发明 名称为“利用顺序号的数据通信协调”的专利申请中所描述的那样。 关于消息的Flags(标志)包括: #define SMB2_FLAGS_SERVER_TO REDIR 0x00000001 当存在时,表明消息是作为相对于请求的响应。 #define SMB2_FLAGS_ASYNC_COMMAND 0x00000002 在响应时,服务器返回具有设置了该标记的STATUS_PENDING以表明我们正 在异步地处理它。 #define SMB2_FLAGS_RELATED_OPERATIONS 0x00000004 在复合消息的客户端消息发送时设置,以表明操作是相关的,所以在Create(创 建)中打开的文件被用为用于稍候操作的FileId。 #define SMB2_FLAGS_SIGNED 0x00000008 当分组已经被签名时设置。接收者应该验证该签名。用于签名的密钥基于发送 分组的会话。 #define SMB2_FLAGS_DFS_OPERATION 0x10000000 这是DFS操作。服务器应该允许DFS对该名称进行字符解析(munge)。这可 被创建选项所代替。 MessageId标识正在被发送的具有它的响应的消息。 ProcessId描述发出命令的过程的客户端侧的标识。 SessionId标识用于命令的建立的会话,或如果没有会话被使用,那么为0。 TreeId标识用于命令的树形连接,或如果没有树形连接被使用,那么为0。 AsynId:如在相关的发明名称为“利用顺序号的数据通信协调”的专利申请中 所描述的那样,消息ID实际上是顺序号,并且可用顺序号的窗口总是被设置成向 右边滑动。会运行相当长时间的命令(诸如指定的管道读取或更改-通知,或取决 于操作锁中断的创建,其中的任何一种能不确定地阻塞)可阻止窗口滑动的能力。 为了解决这个问题,服务器能选择性地响应任何具有STATUS_PENDING并设置以 上提到的SMB2_FLAGS_ASYNC_COMMAND标记以及提供唯一标识符来代替 Session/Tree/ProcessId的命令。这意味着客户端能继续滑动窗口,就好像它接收到 响应。在稍后,具有匹配的AsyncId(和CommandId)的真的响应将到来以满足请 求。在客户端想要取消这样的命令的事件中,客户端发送具有标记设置和匹配的 AsyncId的取消。 除了不再存在隐藏的索引号,安全签名与在先前协议中的一样。借助于对MID 的顺序号的使用,索引不在必要。(这避免直接可重现性)。这允许在不迫使操作在 传送时被排序的情况下对安全签名的使用。 NextCommand是消息中下一命令离开该头部的起始位置的偏移量。消息应该是 四个一行排列的。对SMB2_FLAGS_RELATED_COMMAND的使用允许各种用于 复合的能力,如以上描述的那样。 命令格式 协商(NEGOTIATION) 如以上描述的,客户端和服务器交换协商请求和响应作为帮助它们确定对方能 力的“握手”的一部分。 格式 #define SMB2_NEGOTIATE_SIGNING_ENABLED 0x01 #define SMB2_NEGOTIATE_SIGNING_REQUIRED 0x02 #define SMB2_GLOBAL_CAP_DFS 0x00000001 #define SMB2_GLOBAL_CAp_LWIO 0x00000002 #define SMB2_GLOBAL_CAP_TXF 0x00000004 #define SMB2_GLOBAL_CAP_CSE 0x00000008 typedef struct_SMB2_REQ_NEGOTIATE { USHORT StructureSize; //=sizeof(SMB2_REQ_NEGOTIATE) USHORT Reserved; //=0 ULONG DialectCount; //我们支持的方言数 USHORT Dialects[]; //方言修订版号的数组 }SMB2_REQ_NEGOTIATE,*PSMB2_REQ_NEGOTIATE; typedef struct_SMB2_RESP_NEGOTIATE { USHORT StructureSize; //=sizeof(SMB2_RESP_NEGOTIATE) USHORT SecurityMode; //=签名标记 USHORT DialectRevision; //服务器从接收到的列表中选择的方言 USHORT Reserved; GUID ServerGuid; //服务器授予的GUID ULONG Capabilities; //全局服务器能力标记 ULONG MaxTransactSize; //我们将接受或发送的最大事务缓冲器 ULONG MaxReadSize; //支持的最大大小读 ULONG MaxWriteSize; //支持的最大大小写 UINT64 SystemTime; //服务器上的系统(UTC)时间 USHORT EncryptionKeyOffset; USHORT EncryptionKeyLength; USHORT SecurityBufferOffset; USHORT SecurityBufferLength; UCHAR Buffer[1]; }SMB2_RESP_NEGOTIATE,*PSMB2_RESP_NEGOTIATE; 会话设置(SESSION SETUP) 如以上描述的,会话设置处理用于新会话的鉴别过程。 格式 typedef struct_SMB2_REQ_SESSION_SETUP { USHORT StructureSize; //=sizeof(SMB2_REQ_SESSION_SETUP) USHORT VcNumber; //0=第一连接,非0=其他的连接 ULONG Capabilities; //客户端的能力 ULONG Channel; //非0=把新的信道绑定至会话 USHORT SecurityBufferOffset; USHORT SecurityBufferLength; UCHAR Buffer[1]; //安全缓冲器 }SMB2_REQ_SESSION_SETUP,*PSMB2_REQ_SESSION_SETUP; #define SMB2_SESSION_FLAG_IS_GUEST 0x0001 #define SMB2_SESSION_FLAG_IS_NULL 0x0002 typedef struct _SMB2_RESP_SESSION_SETUP { USHORT StructureSize; //= //sizeof(SMB2_RESP_SESSION_SETUP) USHORT SessionFlags; USHORT SecurityBufferOffset; USHORT SecurityBufferLength; UCHAR Buffer[1]; //安全缓冲器 } 注销(LOGOFF) 注销现有的会话。 格式 typedef struct_SMB2_REQ_LOGOFF{ USHORT StructureSize; USHORT Reserved; }SMB2_REQ_LOGOFF; typedef struct_SMB2_RESP_LOGOFF{ USHORT StructureSize; USHORT Reserved; }SMB2_RESP_LOGOFF; 该命令使用在头部中指定的SessionId把会话拆除。打开的文件被关闭,并且其 他现有的结构(树形连接等)被拆除。对于该给定的SessionId而言,再没有可被 处理的操作。 树形连接(TREE CONNECT) 对在服务器机器上被共享的资源创建树形连接。 格式 typedef struct_SMB2_REQ_TREE_CONNECT { USHORT StructureSize; //=sizeof(SMB2_REQ_TREE_CONNECT) USHORT Reserved; USHORT PathOffset; //完整路径(例如,\\SERVER\SHARE) USHORT PathLength; UCHAR Buffer[1]; }SMB2_REQ_TREE_CONNECT,*PSMB2_REQ_TREE_CONNECT; #define SMB2_SHAREFLAG_MANUAL_CACHING 0x00000000 #define SMB2_SHAREFLAG_AUTO_CACHING 0x00000001 #define SMB2_SHAREFLAG_VDO_CACHING 0x00000002 #define SMB2_SHAREFLAG_NO_CACHING 0x00000003 #define SMB2_SHAREFLAG_CACHING_FLAGS 0x00000003 //Reserved share cap 0x00000001 //Reserved share cap 0x00000002 //Reserved share cap 0x00000004 #define SMB2_SHARE_CAP_DFS 0x00000008//这是DFS共享 #define SMB2_SHARE_TYPE_DISK 0x01 #define SMB2_SHARE_TYPE_PIPE 0x02 typedef struct_SMB2_RESP_TREE_CONNECT { USHORT StructureSize; //=sizeof(SMB2_RESP_TREE_CONNECT) UCHAR ShareType; UCHAR Reserved; ULONG ShareFlags; ULONG Capabilities; }SMB2_RESP_TREE_CONNECT,*PSMB2_RESP_TREE_CONNECT; 客户端向服务器发出该命令以建立树形连接。Path(路径)是\\server\share的 格式并且被填充到缓冲器中。服务器名称的包括在内是考虑到类似共享范围的特 征。 在来自服务器的成功响应时,客户端接收头部内的TreeId和ShareFlags与 ShareCapabilities。当前,共享标记对客户端表明哪些CSC高速缓存器特性是用于 共享的,但是更多的特性可在随后被添加。能力告诉客户端返回共享的文件系统是 否支持文件级安全性、时间异常(timewarp)、TxF(事务文件系统)、或客户端加 密中的任何一种。如果文件系统在某些子树而不是所有子树上(诸如固定点的情况) 支持这些特性,那么应该返回它不支持这些特性并仅仅阻止个体请求在不允许的情 况下使用它们。客户端应该忽略它不理解的任何标记或能力。 树断开连接(TREE DISCONNECT) 拆除现有的TreeConnect。 格式 typedef struct_SMB2_REQ_TREE_DISCONNECT{ USHORT StructureSize; USHORT Reserved; }SMB2_REQ_TREE_DISCONNECT; typedef struct_SMB2_REQ_TREE_DISCONNECT{ USHORT StructureSize; USHORT Reserved; }SMB2_REQ_TREE_DISCONNECT; 一旦命令被处理,在给定的TreeId上不再有操作可被成功完成。TreeId取自于 头部。 创建(CREATE) 打开文件、打印机、或管道。 格式 #define SMB2_OPLOCK_LEVEL_NONE 0 #define SMB2_OPLOCK_LEVEL_II 1 #define SMB2_OPLOCK_LEVEL_EXCLUSIVE 8 #define SMB2_OPLOCK_LEVEL_BATCH 9 #define SMB2_OPLOCK_LEVEL_DIRCHANGE 16 typedef struct_SMB2_REQ_CREATE { USHORT StructureSize; //=sizeof(SMB2_REQ_CREATE) UCHAR SecurityFlags; //QOS安全标记 UCHAR RequestedOplockLevel; //希望的操作锁等级 ULONG ImpersonationLevel; //QOS安全信息 UINT64 SmbCreateFlags; UINT64 RootDirectoryFid; //用于相对的打开 ACCESS_MASK DesiredAccess; ULONG FileAttributes; ULONG ShareAccess; ULONG CreateDisposition; ULONG CreateOptions; USHORT NameOffset; //相对于共享的名称 USHORT NameLength; ULONG CreateContextsOffset; //额外的创建参数 ULONG CreateContextsLength; UCHAR Buffer[1]; //Name[],CreateContexts[] }SMB2_REQ_CREATE,*PSMB2_REQ_CREATE; typedef struct_SMB2_CREATE_CONTEXT { ULONG Next; USHORT NameOffset; USHORT NameSize; USHORT Reserved; USHORT DataOffset; ULONG DataSize; UCHAR Buffer[1];//Name[],Data[] }SMB2_CREATE_CONTEXT,*PSMB2_CREATE_CONTEXT; typedef struct_SMB2_RESP_CREATE { USHORT StructureSize; //=sizeof(SMB2_RESP_CREATE) UCHAR OplockLevel; //授予文件的操作锁 UCHAR Reserved; ULONG CreateAction; //由创建采取的动作 UINT64 FileId; //用于该打开的ID UINT64 CreationTime; //文件时间信息 UINT64 LastAccessTime; UINT64 LastWriteTime; UINT64 LastChangeTime; UINT64 AllocationSize; //文件大小信息 UINT64 EndOfFile; ULONG FileAttributes; //文件的NT属性 ULONG Reserved2; //用于8字节的排列 ULONG CreateContextsOffset; //对于额外创建参数的响应 ULONG CreateContextsLength; UCHAR Buffer[1]; //CreateContexts[] }SMB2_RESP_CREATE,*PSMB2_RESP_CREATE; #define SMB2_CREATE_EA_BUFFER (ULONG)(′AtxE′) #define SMB2_CREATE_SD_BUFFER (ULONG)(′DceS′) #define SMB2_CREATE_MARSHALLED_TRANSACTION (ULONG)(′xTrM′) #define SMB2_CREATE_MINIVERSION (ULONG)(′rVnM′) #define SMB2_CREATE_VERSION (ULONG)(′sreV′) #define SMB2_CREATE_NTFS_FID (ULONG)(′diFN′) #define SMB2_CREATE_TIMEWARP_TOKEN (ULONG)(′prWT′) #define SMB2_CREATE_EFS_STREAM (ULONG)(′sfES′) #define SMB2_CREATE_CLIENT_SIDE_ENCRYPTION (ULONG)(′1ESC′) 创建请求是长度可变的请求以允许用除了传统的明确定义的属性外的各种属 性进行文件的创建。标准的情况(其中没有扩展的属性存在)是简单直接的;客户 端填充RootDirectoryFid(如果希望的话,用于相对的打开)、DesiredAccess、 FileAttributes、ShareAccess、CreateDisposition、以及CreateOptions。它们设置希 望的操作锁等级并填充QoS的SecurityFlags和Impersonation等级。当前,没有定 义的SmbCreateFlags但是有用于它们的使用的被分配好的空间。客户端把该分组 发送至服务器,服务器打开文件并返回失败代码,或返回与标识文件的FileId、 Creation/LastAccess/LastWrite/LastChangeTime、AllocationSize以及EndOfFile信息、 和FileAttributes一起的Success(成功)。 这是与以当前协议操作的方式大部分相同的一般情况。对于更高级的情况,考 虑用户要创建具有扩展属性(EA)的文件。在先前的协议中,有一种通过Transact (事务)调用来处理这个的完全不同的方式。现在,客户端能如一般地建立创建请 求,并也能在创建请求的末端处添加CreateContext。请求将具有名称“ExtA”并 且Data(数据)将包含要设置在文件上的EA。当服务器接收到这个请求时,它会 分析出EA数据并把该EA数据与创建一起发出。创建上下文也能在创建响应时被 返回以提供其他信息。对于第一次迭代,名称长度是4,从而我们能把它们格式成 一样长并在它们上面切换。CreateContext的当前列表如下: 1)“ExtA”-数据包含要放置在创建的文件上的扩展属性。 2)“SecD”-数据包含要放置在创建的文件上的相对于自己的安全描述符。 3)“TWrp”-数据包含应该被用于寻找要打开的文件的时间异常时间标记。 时间标记采用系统时间格式。 4)“MrTx”-数据包含当事务性地打开文件时要被使用的编组的事务。 5)“MnVr”-数据包含最小版本号(ULONG)以打开处理的文件。 6)“Vers”-数据包含打开的文件(创建响应)的版本号(ULONG)。 7)“NFid”-数据包含打开的文件(创建响应)的NTFS Fid (LARGE_INTEGER)。 8)“$Efs”-数据包含要被标记在新的加密文件上的$EFS流。 9)“CSE1”-数据包含打开的加密文件(创建响应)的$EFS流。 由于服务器的支持,更多的CreateContext值可被添加。(由于值被添加,它们具有 或与它们关联或与新方言版本关联的能力位,以使客户端在发出创建请求之前知道 服务器支持哪些标记)。接收具有未被识别的上下文标记的创建请求的服务器会使 该请求失败。 关闭(CLOSE) 客户端发送Close以关闭先前被打开的文件的实例。一旦关闭被处理,那么在 先前的FID上没有文件操作被允许。 格式 typedef struct_SMB2_REQ_CLOSE{ USHORT StructureSize; USHORT Reserved; ULONG Flags; UINT64 FileId; UINT64 LastWriteTime; }SMB2_REQ_CLOSE,*PSMB2_REQ_CLOSE; typedef struct_SMB2_RESP_CLOSE{ USHORT StructureSize; USHORT Reserved; }SMB2_RESP_CLOSE,*PSMB2_RESP_CLOSE; 对于Close命令,客户端指定正被关闭的文件的FileId和LastWriteTime(以 SystemTime格式)。这允许客户端设置在文件上被执行的高速缓存的写的最后时间 作为对该文件的最后写时间。客户端也能发送0的LastWriteTime以表明它们不希 望指定一个时间。该结构也对当前没有被定义的、但可能在随后被定义的Close标 记分配空间。 清除(FLUSH) 清除命令通知服务器清除关于给定的文件的所有高速缓存的数据。 格式 typedef struct_SMB2_REQ_FLUSH{ USHORT StructureSize; USHORT Reserved1; ULONG Reserved2; UINT64 FileId; }SMB2_REQ_FLUSH,*PSMB2_REQ_FLUSH; typedef struct_SMB2_RESP_FLUSH{ USHORT StructureSize; USHORT Reserved; } 在从服务器接收成功响应时,客户端被保证所有高速缓存的数据已经被清除到 它们备份持久存储。客户端指定它希望清除的文件的FileId。直到所有数据从管道 中消除,该管道上的清除才返回,这需要花费一些时间。 读(READ) 从打开的文件中读数据。 格式 typedef struct_SMB2_REQ_READ { USHORT StructureSize; //=sizeof(SMB2_REQ_READ) UCHAR Padding; //从头部的开始处请求的读数据响应的填充 UCHAR Reserved; ULONG Length; //在该信道上发送的读的长度 UINT64 Offset; //读的偏移量 UINT64 FileId; //文件的标识符 ULONG MinimumCount; //读并被考虑为成功的最小字节 ULONG Channel; //在其上发送剩余数据的信道 ULONG RemainingBytes; //如果信道!=0,额外的字节被读取并在信道上发送, //否则为计划还要读多少 USHORT ReadChannelInfoOffset;//如果信道!=0,为关于要在其上发送额外数据的信道的 信息 USHORT ReadChannelInfoLength; UCHAR Buffer[1]; //ReadChannelInfo }SMB2_REQ_READ,*PSMB2_REQ_READ; typedef struct_SMB2_RESP_READ { USHORT StructureSize; //=sizeof(SMB2_RESP_READ) UCHAR DataOffset; //对于包内的数据的偏移量 UCHAR Reserved; ULONG DataLength; //作为这个分组的一部分的数据返回的长度 ULONG DataRemaining; //正在备选信道(如果指定)上发送的数据的长度, //否则为我们准备再要读多少数据 UCHAR Buffer[1]; //Pad[],Data[] }SMB2_RESP_READ,*PSMB2_RESP_READ; 读是非常明显的。客户端指定读的文件(通过FileId)、偏移量、以及长度,并 且服务器返回数据。客户端能指定几个其他属性。MinCount告诉服务器用于成功 返回的它能从文件中读取的最大量。如果读是短的,那么服务器仅仅返回失败而不 返回整个数据缓冲器。为了更好的处理,客户端也能推荐填充(Padding)。这是在 服务器应该放置数据的读响应分组内的偏移量。这允许客户端当从传送中接收下信 息时以更有效的方式拟定读响应缓冲器。剩余字段向服务器表明如果这只是读的一 部分,则整个读将有多少。如此,如果客户端正准备以1k信息块的方式读8k,那 么它将发出读1k并且剩余(Remaining)=7k。这允许服务器具有通过在一个操作 内读取整个8k并把数据缓冲回客户端来优化的选项。 在服务器响应时,它表明多少数据正在返回(在DataLength字段内)以及在读 命令中指定的DataRemaining。 如果在命令中指定的信道不是命令参与的信道,那么用户请求信道读。这意味 着如果我使用“信道=1”和“长度=0,剩余=64k”请求在信道0上读,那么服 务器将响应“DataLength(数据长度)=0,DataRemaining(数据剩余)=64k”以 及接下来来自信道1的64k字节将是数据。客户端负责使此同步以使当该命令发出 时,确保在信道1上没有未完成的数据响应。客户端也能发出(在信道0上)“读 信道=1,数据长度=1k,剩余=7k”,以使响应会包含数据的第一个1k以及剩余 的数据(最后7k)可流过信道1。 写(WRITE) 对打开的文件写数据。 格式 typedef struct_SMB2_REQ_WRITE { USHORT StructureSize; //=sizeof(SMB2_REQ_WRITE) USHORT DataOffset; //数据离开头部的偏移量 ULONG Length; //正在被写的数据的长度 UINT64 Offset; //写的文件偏移量 UINT64 FileId; //正在被写入的文件的标识符 ULONG Channel; //如果是非0,剩余数据应在其上发送的信道 ULONG Remaining; //在信道上被发送的字节数 USHORT WriteChannelInfoOffset; //如果信道!=0,我们希望对其写数据的信道的信息 USHORT WriteChannelInfoLength; ULONG Flags; UCHAR Buffer[1]; //WriteChannelInfo }SMB2_REQ_WRITE,*PSMB2_REQ_WRITE; typedef struct_SMB2_RESP_WRITE { USHORT StructureSize; //=sizeof(SMB2_RESP_WRITE) USHORT Reserved; ULONG Count; //被写的数据的量 ULONG Remaining; //我们能在信道上接收的字节的数量 USHORT WriteChannelInfoOffset; //如果信道!=0,我们希望对其写数据的信道的可选信息 USHORT WriteChannelInfoLength; UCHAR Buffer[1]; //WriteChannelInfo }SMB2_RESP_WRITE,*PSMB2_RESP_WRITE; 客户端填充文件(由FileId标识)、偏移量、写的长度、以及附加的数据。推荐 数据被填充在原始协商响应内被返回以帮助服务器性能。客户端也能表明将对服务 器再写多少数据以允许服务器最优化。在响应时,服务器表明写了多少,并返回它 依然期待的量。 如果在写内指定的信道不是命令参与的信道,那么客户端请求在另一信道上流 式传输数据。一个例子是具有“信道=1,长度=0,剩余64K”的在信道0上接收 到的写。客户端请求在信道1上流式传输64k写。服务器会响应“计数=0,剩余 =64k”以允许写。该响应将包括在数据被在信道上发送和确认之后将到来的第二 响应的AsyncId。然后,接下来的在信道1上流式传输的64k字节将是数据。(没 有头部)。在完成之后,服务器将在信道0上发送SMB2_RESP_WRITE以表明操 作的成功/失败,并使用AsyncId信息发送第二回复,除非该指定信道允许内在确 认,这种情况下它将在信道上发生。 打开操作锁(BREAK_OPLOCK) 被用以请求和确认在文件上采用的机会锁(opportunistic lock)的释放。 格式 typedef struct_SMB2_REQ_BREAK_OPLOCK { USHORT StructureSize; //=sizeof(SMB2_REQ_BREAK_OPLOCK) UCHAR OplockLevel; //打开到的级别.(级别2or无级别) UCHAR Reserved; ULONG Reserved2; //超时(单位秒) UINT64 FileId; //正在被上锁/解锁的文件的标识符 }SMB2_REQ_BREAK_OPLOCK,*PSMB2_REQ_BREAK_OPLOCK; typedef struct_SMB2_RESP_BREAK_OPLOCK { USHORT StructureSize; //=sizeof(SMB2_RESP_LOCK) UCHAR OplockLevel; //已打开到的级别(<=请求的级别) UCHAR Reserved; ULONG Reserved2; UINT64 FileId; }SMB2_RESP_BREAK_OPLOCK,*PSMB2_RESP_BREAK_OPLOCK; 当另一用户请求访问该客户端以需要打开现有的锁的形式对其保持机会锁的 文件时,SRV将发送SMB2_RESP_BREAK_OPLOCK至客户端。然后,客户端被 期待发送给定文件的REQ_BREAK_OPLOCK以释放它们的操作锁,并且SRV将 再次响应以确认。 锁(LOCK) 被用以请求字节范围锁,并也被用以请求机会锁(以及当机会锁被打开时通知 客户端)。 格式 #define SMB2_LOCKFLAG_SHARED_LOCK 0x01 #define SMB2_LOCKFLAG_EXCLUSIVE_LOCK 0x02 #define SMB2_LOCKFLAG_UNLOCK 0x04 #define SMB2_LOCKFLAG_FAIL_IMMEDIATELY 0xl0 typedef struct_SMB2_LOCK { UINT64 Offset; UINT64 Length; ULONG Flags; ULONG Reserved; }SMB2_LOCK,*PSMB2_LOCK; typedef struct_SMB2_REQ_LOCK { USHORT StructureSize; //=sizeof(SMB2_REQ_LOCK) UCHAR LockCount; ULONG Reserved; UINT64 FileId; //正在被上锁/解锁的文件的标识符 SMB2_LOCK Locks[1]; //大小的数组(LockCount) }SMB2_REQ_LOCK,*PSMB2_REQ_LOCK; typedef struct_SMB2_RESP_LOCK { USHORT StructureSize; //=sizeof(SMB2_RESP_LOCK) USHORT Reserved; }SMB2_RESP_LOCK,*PSMB2_RESP_LOCK; LOCK请求的语法类似于SMB1Lock请求的语法。客户端指定FileId,以及一 个或多个表明它们希望上锁的偏移量和长度的SMB_LOCK结构。所有这些LOCK 结构必须是上锁或解锁。然而,你能把共享的和专有的锁请求混合在单批锁操作中。 对于锁分批的最普遍的使用是要求一系列锁作为一批操作锁打开(oplock break) 的一部分,当你保证所有的锁将成功时这个是最有用的。 成功返回向客户端表明它们获取(或释放)请求的字节范围锁。在失败的情况 下,字节范围锁不被授予。 回送(ECHO) 回送由客户端使用以及时确定服务器是否依然在给定的点上。在接收这个命令 后,服务器将仅仅把它回转并返回成功。 格式 typedef struct_SMB2_REQ_ECHO{ USHORT StructureSize; USHORT Reserved; }SMB2_REQ_ECHO,*PSMB2_REQ_ECHO; typedef struct_SMB2_RESP_ECHO{ USHORT StructureSize; USHORT Reserved; }SMB2_RESP_ECHO,*PSMB2_RESP_ECHO; 服务器对分组进行响应以表明它正常工作。用于允许客户端对服务器进行 “ping”。 取消(CANCLE) 由客户端使用以请求对已发送的操作的取消。 格式 typedef struct_SMB2_REQ_CANCEL{ USHORT StructureSize; USHORT Reserved; }SMB2_REQ_CANCEL,*PSMB2_REQ_CANCEL; 取消没有响应,但应该导致命令本身被成功地完成,或以 STATUS_CANCELLED失败,并且这应该是尽快发生的。由于正在被发送的操作 将共享取消命令的MessageId,所以它被标识。这是一种发送到服务器的MessageId 已经被先前使用的情况。如果响应伴随应该存在于头部内的AsyncId到来,那么会 被用以在服务器上定位命令。 IOCTL Ioctl被用以通过网络发出设备控制或文件系统控制命令。 格式 //请求 typedef struct_SMB2_REQ_IOCTL { USHORT StructureSize; //=sizeof(SMB2_REQ_TRANSACT) USHORT Reserved; ULONG CtlCode; UINT64 FileId; ULONG InputOffset; //用于输入缓冲器的字节 ULONG InputCount; //在该消息内的参数字节计数 ULONG MaxInputResponse; //服务器能返回响应参数的最大字节 ULONG OutputOffset; //数据字节位置 ULONG OutputCount; //在该消息内的数据字节计数 ULONG MaxOutputResponse; //服务器能返回响应数据的最大字节 ULONG Flags; ULONG Reserved2; UCHAR Buffer[1]; //参数[],数据[] }SMB2_REQ_IOCTL,*PSMB2_REQ_IOCTL; //响应 typedef struct_SMB2_RESP_IOCTL { USHORT StructureSize; //=sizeof(SMB2_RESP_TRANSACT) USHORT Reserved; ULONG CtlCode; UINT64 FileId; ULONG InputOffset; //用于输入缓冲器的字节 ULONG InputCount; //在该消息内的参数字节计数 ULONG OutputOffset; //数据字节位置 ULONG OutputCount; //在该消息内的数据字节计数 ULONG Flags; ULONG Reserved2; UCHAR Buffer[1]; //参数[],数据[] }SMB2_RESP_IOCTL,*PSMB2_RESP_IOCTL;}SMB2_RESP_TRANSACT,*PSMB2_RESP_TRANSACT; IOCTL被用于通过网络发出一般的文件系统或设备控制命令。它基于控制代码 的METHOD(方法)把输入和输出缓冲器打包并通过网络发送它们。然后,服务 器方重新把它们封装并发出针对文件对象的FSCTL/IOCTL。结果被同样地打包并 与状态代码一起被返回到用户。可允许的FSCTL/IOCTL代码组可由SRV或底层 文件系统限制。(不是所有的都必须远程地有效)。 对于缓冲的或直接的请求,仅仅Input(输入)在请求上是有效的,并且Output (输出)在响应上被发送。对于不是这样的请求,输入和输出通过两种方式发送。 查询目录(QUERY DIRECTORY) 允许客户端通过网络查询在打开目录句柄上的目录枚举。 格式 // //QUERY_DIRECTORY命令 // #define SMB2_REOPEN 0x10 //请求 typedef struct_SMB2_REQ_QUERY_DIRECTORY { USHORT StructureSize; //= //sizeof(SMB2_REQ_QUERY_DIRECTORY) UCHAR FileInformationClass; UCHAR Flags; //SL_/SMB2_flags ULONG FileIndex; UINT64 FileId; USHORT FileNameOffset; USHORT FileNameLength; ULONG OutputBufferLength; UCHAR Buffer[1]; //FileName参数 }SMB2_REQ_QUERY_DIRECTORY,*PSMB2_REQ_QUERY_DIRECTORY; //响应 typedef struct_SMB2_RESP_QUERY_DIRECTORY { USHORT StructureSize; //=sizeof(SMB2_RESP_QUERY_DIRECTORY) USHORT OutputBufferOffset; ULONG OutputBufferLength; UCHAR Buffer[1]; //响应数据 }SMB2_RESP_QUERY_DIRECTORY,*PSMB2_RESP_QUERY_DIRECTORY; QueryDirectory调用非常匹配现有的NT语义。调用者提供用于目录打开的 InfoClass、FileId、filename(文件名)部分(指定通配符/文件搜索参数或用于现有 搜索的概要名称)以及任何有效的与调用关联的SL_标记,SRV将返回一缓冲器 直到OutputBufferLength。 也存在能被包括在QueryDirectory标记结构内的新的标记(SMB2_REOPEN)。 该标记是SL_RESTART_SCAN标记的更强的版本。SL_RESTART_SCAN标记仅仅 允许重新开始扫描指定的搜索没有更改的部分。(也就是说,重新开始*.*或t*搜 索)。SL_RESTART_SCAN标记告诉服务器重新开始扫描指定的搜索已经更改的部 分。为了使用该标记,调用者必须保证调用中的专用且没有未完成的操作(诸如更 改通知)。服务器采取适当的步骤执行该操作,这可涉及在服务器方关闭和重新打 开底层的目录句柄。这对于客户端而言是透明的。 更改通知(CHANGE NOTIFY) 该潜在的长时间运行的操作允许客户端在目录上登记更改通知。 格式 // //CHANGE_NOTIFY命令 // //请求 typedef struct_SMB2_REQ_CHANGE_NOTIFY { USHORT StructureSize; //= //sizeof(SMB2_REQ_CHANGE_NOTIFY) USHORT Flags; //SL_WATCH_TREE? ULONG OutputBufferLength; UINT64 FileId; ULONG CompletionFilter; ULONG Reserved; }SMB2_REQ_CHANGE_NOTIFY,*PSMB2_REQ_CHANGE_NOTIFY; //响应 typedef struct_SMB2_RESP_CHANGE_NOTIFY { USHORT StructureSize; //= //sizeof(SMB2_RESP_CHANGE_NOTIFY) USHORT OutputBufferOffset; ULONG OutputBufferLength; UCHAR Buffer[1]; //通知数据 }SMB2_RESP_CHANGE_NOTIFY,*PSMB2_RESP_CHANGE_NOTIFY; 调用者发送目录的FileId和指定调用者感兴趣的更改的CompletionFilter。它们 也能发送SL_WATCH_TREE标记以表明循环的通知操作。由于该操作可能等待无 限的时间,因此它几乎总是调用“async(异步)”行为。也需要注意的是任何其他 关于相同句柄的更改通知请求将等待第一个请求的完成,正如在本地文件系统行为 中的那样。 查询信息(QUERY INFO) 允许客户端从远程系统中查询信息。当前,这可被用以查询文件信息、文件- 系统信息、安全信息、或配额信息。 格式 // //QUERY_INFO // #define SMB2_0_INFO_FILE 0x01 #define SMB2_0_INFO_FILESYSTEM 0x02 #define SMB2_0_INFO_SECURITY 0x03 #define SMB2_0_INFO_QUOTA 0x04 typedef struct_SMB2_QUERY_QUOTA_INFO{ UCHAR ReturnSingleEntry;//表明仅仅应该返回单个条目而不是向缓冲器填充尽可能多的 条目 UCHAR RestartScan; //表明配额信息的扫描是否要从头重新开始 USHORT Reserved; ULONG SidListLength; //提供SID列表(如果存在)的长度 ULONG StartSidLength; //提供可选的SID,该SID表明返回的信息要开始于 //不是第一个条目的条目。如果给定SidList,那么该参数被 忽略 ULONG StartSidOffset; //提供缓冲器内开始Sid的偏移量 }SMB2_QUERY_QUOTA_INFO,*PSMB2_QUERY_QUOTA_INFO; //Request typedef struct_SMB2_REQ_QUERY_INFO { USHORT StructureSize; //=sizeof(SMB2_REQ_QUERY_INFO) UCHAR InfoType; //确定信息类型 //(SMB2_0_INFO_*) UCHAR FileInfoClass; ULONG OutputBufferLength; USHORT InputBufferOffset; //输入缓冲器仅仅在Quota(配额)调用上有效 USHORT Reserved; ULONG InputBufferLength; union{ ULONG SecurityInformation; //用于Query Security(查询安全)调用 ULONG EaIndex; //用于QueryEA调用 }; ULONG Flags; UINT64 FileId; UCHAR Buffer[1]; }SMB2_REQ_QUERY_INFO,*PSMB2_REQ_QUERY_INFO; //Response typedef struct_SMB2_RESP_QUERY_INFO { USHORT StructureSize; //=sizeof(SMB2_RESP_QUERY_INFO) USHORT OutputBufferOffset; ULONG OutputBufferLength; UChAR Buffer[1]; //文件信息 }SMB2_RESP_QUERY_INFO,*PSMB2_RESP_QUERY_INFO; 客户端在InfoType内指定SMB2_0_INFO_*选项以表明这是否是对于文件信 息、文件系统信息、安全信息、或配额信息的请求。FileId指示正在被讨论的文件 (用于文件信息或安全信息)。文件所驻留的卷(volume)被用于文件系统信息或 查询请求。 子信息等级被填充到FileInfoClass,并且取决于正在被查询的信息的类型。对 于文件信息查询,它是FILE_INFORMATION_CLASS,而对于文件系统信息,它 是FS_INFORMATION_CLASS。对于配额和安全,它是0。 输入缓冲器当前仅仅用于Quota请求,因为它们在输入上采用 SMB2_QUERY_QUOTA_INFO结构以确定正在被请求的内容。对于其他请求,它 是空。 OutputBufferLength指定返回给用户的数据的最大量。 设置信息(SET INFO) 允许客户端在远程系统上设置信息。当前,这可被用以设置文件信息、文件- 系统信息、安全信息、或配额信息。 格式 // //SET_INFO // //请求 typedef struct_SMB2_REQ_SET_INFO { USHORT StructureSize; //=sizeof(SMB2_REQ_SET_INFO) UCHAR InfoType; UCHAR FileInfoClass; ULONG BufferLength; USHORT BufferOffset; USHORT Reserved; union{ ULONG Reserved2; ULONG SecurityInformation;//用于SET_SECURITY调用 }; UINT64 FileId; UCHAR Buffer[1]; //文件信息 }SMB2_REQ_SET_INFO,*PSMB2_REQ_SET_INFO; //Response typedef struct_SMB2_RESP_SET_INFO { USHORT StructureSize; //=sizeof(SMB2_RESP_SET_INFO) }SMB2_RESP_SET_INFO,*PSMB2_RESP_SET_INFO; 正在被设置的信息的类型以及特定的类在Flags和FileInfoClass字段内被设置, 如对QUERY_INFO描述的那样。提供的输入缓冲器是正在被设置的信息,并且 FileId标识文件。 对于SetSecurity调用,SecurityInformation字段指示正在被设置的信息。(即, OWNER_SECURITY_INFORMATION等) 结论 尽管本发明受各种修改和可供选择的构造的影响,其中说明的某些实施例已经 在附图中显示并在以上被详细描述。然而,应该理解的是本发明不被限制于公开的 特定形式,相反,本发明涵盖所有的在本发明的精神和范围内的修改、可供选择的 构造、和等同物。 有关申请的交叉参考 本申请要求于2005年5月25日提交的美国临时专利申请第60/685,008号的 优先权,并且该专利申请引用在此作为参考。本申请涉及同时提交的、被转让于本 发明的受让者的发明名称为“Data Communication Coordination with Sequence Numbers”(利用顺序号的数据通信协调)的、代理人档案号为5660/313764的共同 待批的美国专利申请,该专利申请引用在此作为参考。