在RDP远程桌面协议中,USB设备虚拟通道扩展协议用于将USB数据包从终端服务器传输到终端客户端。终端客户端将USB数据包转发到物理USB设备。然后客户端在物理设备重新组装数据包后返回结果。
一般来说,远程访问的协议可以重定向USB设备,所以在使用和过程中,必须为客户端提供一种方式来指定使用该协议重定向的USB设备,或者选择使用替代方法的设备或者完全不重定向的设备。因为当设备被重定向时,它就不能在客户端上继续使用。例如:
USB鼠标:如果使用此协议进行USB鼠标重定向,那么在客户端本地将无法使用鼠标。这种结果实用与虚拟桌面全屏使用的场景,但是在传统的RDP服务中,我们的客户端和服务器端都需要同时复用我们的鼠标设备,因此,RDP协议的USB虚拟通道如何解决这个问题?
面对这个问题,我们不从RDP协议USB虚拟通道本身的实现上去思考,而是以我们自身先思考如何来解决这个问题为前提。那么解决办法有两种途径:
1、使用免驱动的鼠标;
2、客户端使用两个鼠标。
第一个方案似乎很好,但是有限制条件,那就不完美了;第二个条件就纯粹是一种反人类的方案,直接pass。我们发现似乎只有在协议上做优化,才能够完美兼容当前的使用习惯和操作体验。
这就涉及到RDP协议的USB虚拟通道采用什么完美机制来实现上述的需求了。针对这个问题,我们来了解RDP协议的USB虚拟通道是如何工作的?以解我们上述的疑问吧!
首先我们需要先讲几个概念:
1、设备驱动程序:系统用来与设备(如显示器、打印机、鼠标或通信适配器)通信的软件。其是一个抽象层,用于控制应用程序访问给定计算机系统上的各种硬件设备。我们通常将其简称为“驱动”。那么驱动是如何和硬件进行通信的?这个就涉及到每个硬件的寄存器了。我之前写过一篇介绍应用程序如何通过驱动去实现和硬件的交互,里面介绍了这方面的内容,包括驱动如何去找到硬件的寄存器地址以及如何与寄存器进行交互。
2、设备接口:一种统一且可扩展的机制,可以与应用程序和系统以编程方式进行交互。设备驱动程序可以为特定设备提供一个或多个设备接口。设备接口由GUID(全球唯一标识符)表示。
3、远程设备:连接到远程(或客户端)机器的设备。
4、终端客户端:终端服务器的客户端。在客户机上运行的终端客户机程序。在Windows中,RDP只是一个协议,实现我们可以访问服务器桌面并显示图像,为这个协议提供显示资源和交互资源是名叫终端服务,在高版本中改为远程桌面服务。
5、终端服务器:运行终端服务的服务器。
就上述问题而言,RDP协议的USB虚拟通道使用了比较灵活的设计来保证使用的灵活性,首先将需要重定向那些USB设备的决定权交给了用户,由用户来给予明确的答案。
执行这些规则和策略,我们在Windows的终端客户端上就可见一斑,这就是用于选择正确设备的用户界面,而这些都只是常见的设备,比较全的执行此类规定的还是和Windows的其他服务相集成:组策略、注册表、通知等。因此和其他协议类似,灵活性选择重定向的设备是这个设计的满足当前的使用习惯和操作体验比较完美的一种解决方案。
其次,针对USB鼠标复用的问题,在协议上解决我想RDP的USB虚拟通道和其他协议并无区别,都是基于“会话”和“焦点”的判断来自动对USB鼠标进行切换,已达到复用USB鼠标的目的。会话应该很好理解,启动一个远程桌面连接就是一个会话,会话的属性就包括用户、连接密码、连接地址等等。而焦点,则是判断用户当前的桌面是位于本地客户端还是远程桌面。
下面我们具体来介绍RDP协议的USB虚拟通道是如何工作的。
在USB虚拟通道的实现中,终端客户端的USB硬件设备需要重定向到终端服务器上,那么首先需要终端客户端和硬件USB设备进行连接,然后将设备通过RDP协议客户端重定向到终端服务器上。终端服务器要识别硬件USB设备,就必须在服务器上安装设备驱动程序。
下图描述了USB设备和服务器上的USB驱动程序堆栈有关的事件序列。
图1:USB堆栈流
当插入USB设备时,客户端向服务器发送添加虚拟通道消息。作为响应,服务器发送也发送一个相同的虚拟通道创建消息给到客户端,并等待来自客户端的相同消息。客户端发送虚拟通道创建消息后,客户端立即发送添加设备消息,待双方都创建虚拟通道完毕后互相发送消息确认完毕,服务器立即开始创建一个USB驱动程序堆栈,驱动程序将向系统表示该USB设备的存在。此后,服务器和客户端就可以准备交换I / O数据包了。
当设备从客户端拔出时,协议就会关闭服务器发送给特定设备的I/O通道。
具体来说,USB设备虚拟通道的建立和交换数据,都需要遵循以下的逻辑顺序:
1、通道设置顺序:打开通道,并交换能力。该通道被分配由客户端和服务器用来识别USB设备的特定标识符。USB设备虚拟通道在单个命名的动态虚拟通道中使用多个通道。每个USB设备有一个控制通道和一个数据通道。此序列的目标是设置通道的标识符并交换硬件标识和版本功能。
图2:通道设置顺序
2、新设备顺序:客户端通知服务器新设备到达。服务器在服务器计算机上创建与客户端报告的设备相对应的设备。客户端使用新的设备序列来通知服务器有关新设备。它首先通知服务器创建USB重定向虚拟通道的新实例。一旦创建了新的虚拟通道,则经由新的虚拟通道将新的设备消息发送到服务器。根据添加设备消息的HardwareIds字段识别设备。
图3:新设备序列
3、I/O序列:服务器向客户端发送USB数据包,客户端将USB数据包转发到物理设备,并在物理设备重新组装数据包后发送回结果。服务器使用I/O序列向客户端发送I/O请求。 在RDP协议的USB虚拟通道中,服务器可以向客户端发送多个I/ O请求,而不用等待先前发送的请求完成。
图4:I/O序列
USB设备虚拟通道嵌入在动态虚拟通道传输中,动态通道虚拟通道扩展在虚拟通道协议之上实现通用的面向连接的通信通道。动态虚拟通道(DVC)是在现有建立的静态虚拟通道之上。静态虚拟通道会话是典型的客户端/服务器关系。远程桌面协议(RDP)层【RDP协议的架构层次】管理虚拟通道上通道创建、设置和数据传输。DVC由通过网络逻辑连接的两个端点组成。一个端点是在终端服务(TS) 服务器上运行的应用程序,另一个端点是运行在终端客户端上的应用程序。DVC由DVC管理器创建和维护。终端服务器和终端客户端上都有一个DVC管理器。DVC服务器管理器负责初始化DVC环境和创建单独的DVC。DVC客户端管理器负责创建和维护与客户端DVC管理器应用程序的连接。在DVC管理器初始化之后,DVC服务器管理器可以创建单独的DVC。这些通道用于在运行在终端服务器上的应用程序和在终端客户端上运行的DVC监听程序之间交换消息。发送和接收消息在客户端和服务器之间是对称的,双方都可以发起发送数据消息(或消息)。
因此,USB虚拟通道实质是想建立静态的客户端/服务器关系的虚拟通道,然后再通过静态虚拟通道之上,由动态虚拟通道管理器创建相互之间的交换数据通道。静态虚拟通道和动态虚拟通道之间的转换是这样的:
USB设备虚拟通道仅在动态虚拟通道传输完全建立后运行。如果动态虚拟通道传输被终止,USB设备虚拟通道也被终止。也就是USB设备被手动拔出,那么动态虚拟通道就被终止了,相应的USB设备虚拟通道也被终止,就会在服务器端的消息中提示USB设备已拔出,这个消息将会是通过静态的虚拟通道数据交换通道发出。而通过关闭底层虚拟通道来终止协议,那么就直接关闭掉RDP会话的连接。底层虚拟通道终止,动态虚拟通道就被终止,USB设备虚拟通道也被终止。
除了重定向设备,我们还可以重定向USB设备的驱动程序以及应用程序。如果要重定向设备驱动程序和应用程序,则必须满足以下要求:
1、设备和应用程序之间的所有通信都通过设备驱动程序支持的I/O序列进行路由。通信不能通过任何其他方式进行路由,例如共享内存,注册表或磁盘文件。
2、设备驱动程序和应用程序之间的通信不能是除了这些基本调用【读,写和IO控制】之外的任何东西。
为什么呢?因为协议格式字段规定和限制了传输的调用使用。
最后我提一个问题:
如果我有一台带有双显卡的计算机,两个显示器、两个鼠标和两个键盘。假设我将其分配给两个人同时使用这台计算机,其中第一个显示器使用本地计算的操作系统,在第二个显示器的窗口中通过远程桌面打开RDP会话,提供给第二个用户使用。那么我该通过什么方式进行设置,使得两个鼠标和两个键盘互不干扰,第一个鼠标和键盘专用于本地系统,第二个鼠标和键盘专用于RDP会话?