http://hi.baidu.com/tulkphakyfbdmse/item/0872921f618c9affdceecaca
Windows管道系统 - 第一篇
Windows存在两种类型的管道: “匿名管道”(Anonymous pipes)和”命名管道”(Named pipes)。匿名管道相比命名管道需要较小的开销,同时它也只提供有限的系统服务。
术 语管道用在这里,毫无疑问地它是作为了一种信息交换的渠道。概念上一个管道有A、B两个端点。一个单路(“One-way”)管道允许在A端的进程向管道 写入数据,允许在B端的进程从管道读出数据。而一个双路(或双通道)管道允许进程在管道的A、B两端读、写数据。下面我们就从匿名管道和有名管道两方面来 介绍一下Windows的管道机制。
匿名管道一个匿名管道是一个没有名字、单路(“One-way”)管道,它典型的应用场景就是在父进程和子进程之间传输数据。匿名管道仅限用于本机通讯,它不能被用于跨网络通讯的场合。
匿名管道的操作CreatePipe 函数用于创建一个匿名管道并返回两个句柄:一个管道读句柄和一个管道写句柄。这个管道读并举拥有对管道的只读访问权限,而这个管道写句柄拥有对管道的只写 访问权限。为了通过管道进行通讯,管道服务端必须通过某种方法将管道句柄传给另一个进程。这通常通过进程间的继承性来完成的;即,进程允许将句柄继承给它 的子进程。进程也可以通过DuplicateHandle函数来复制管道句柄并将得到的管道句柄副本通过其它进程间通讯手段(例如众所周知的共享内存、 DDE – 动态数据交换或者消息)发送给一个无关进程。
一个管道服务端可以发送管道读句柄或管道写句柄给管道客户端,具体发送哪个句柄这 要取决于客户端使用管道是要发送信息还是接受信息而已!为了从管道读取数据,我们使用管道读句柄来调用ReadFile函数,当另外一个进程向管道中写入 了数据ReadFile调用就会返回,再者当所有的管道写句柄都已关闭或者当读操作完成前发生了错误都会导致ReadFile调用返回。
对 于管道的写操作,我们使用管道写句柄来调用WriteFile函数,WriteFile调用不会返回直到它向管道写入了指定数量的字节或者中途产生了异 常。如果管道缓冲区已经塞满并且还有更多的数据没有写入管道,那么WriteFile调用也不会返回直到另一个进程从管道中读出数据以释放出有效的管道缓 冲区(来盛放其余的数据)。管道缓冲区的大小由管道服务端在创建管道(CreatePipe)时指定。
匿名管道不支持异步(重叠)读、写操作。这意味着你不能使用ReadFileEx、WriteFileEx函数来操作匿名管道。另外,对于ReadFile、WriteFile函数在操作匿名管道时lpOverlapped参数都将被忽略。
一个匿名管道对象只有当所有的管道读、写句柄都被关闭后才会被释放,否则它将一直存在!进程可以使用CloseHandle函数来关闭它的管道句柄,当进程终止时所有管道句柄也将随之被(系统自动)关闭。
匿名管道机制是通过一个名字全局唯一的有名管道来实现的。因此,你可以将一个匿名管道句柄传递给一个需要一个有名管道句柄的函数(这听起来好像有点拗口)!
管道句柄的继承管道服务端控制着它的句柄是否能以如下方式被继承:
l CreatePipe函数接受一个SECURITY_ATTRIBUTES结构,如果管道服务端设置SECURITY_ATTRIBUTES结构的bInheritHandle成员为TRUE的话,CreatePipe创建句柄就是能被继承;
l 管道服务端可以使用DuplicateHandle函数来改变管道句柄的继承性。管道服务端可以创建一个“可继承管道句柄”的不可继承的副本或者一个“不可继承管道句柄”的可继承的副本。
l CreateProcess函数的bInheritHandles参数赋予了管道服务端是否使其子进程继承所有或不继承它的可继承句柄的能力。
当子进程继承了一个管道句柄,系统就赋予了进程访问这个管道的能力。然而,父进程必须以某种方式告知子进程关于这个管道句柄的值!父进程告知子进程的典型做法是通过重定向标准输出句柄到子进程,步骤如下(下面1~4都是针对父进程而言):
1. 调用GetStdHandle函数获取当前标准输出句柄并保存该句柄(后面当子进程创建结束后你可以使用该值来恢复原来的标准输出句柄);
2. 调用SetStdHandle函数把管道写句柄设置为标准输出句柄,现在父进程可以创建子进程了。
3. 调用CloseHandle函数关闭管道写句柄,当子进程继承这个管道写句柄后,父进程就不再需要它的那份(管道写句柄的)拷贝了。
4. 调用SetStdHandle函数来恢复原来的标准输出句柄。
当子进程创建成功以后,子进程就可以使用GetStdHandle函数来获取它的标准输出句柄了,而现在这个标准输出句柄就是指向管道写句柄!子进程接着就可以使用WriteFile函数来向管道写入数据(也就是发送数据)。当子进程使用完管道,它应该调用CloseHandle函数关闭管道句柄,或者进程终止时由系统自动关闭管道句柄。
父进程使用ReadFile函数从管道中接收数据,而数据是以字节流方式被写进匿名管道的。这就意味着父进程从管道中读取数据是无法区分写进去的字节是在单独不同的写操作中完成的,除非父进程和子进程之间使用一种协议来指示写操作在何处结束。当所有的管道写句柄都被关闭时,ReadFile函数就返回0,“在调用ReadFile之前先关闭管道写句柄”这一点对父进程来说至关重要的!如果这点你没有做,ReadFile函数是不会返回0的,这是因为父进程还有一个处于打开状态的管道写句柄未关闭!
注:重定向标准输入句柄和重定向标准输出句柄的过程十分相似,除了管道的读句柄被用作子进程的标准输入句柄外其它基本相同。用这种方式,父进程必须确保子进程没有继承管道写句柄。如果这点你没有做,ReadFile函数被子进程执行是不能返回0的,因为子进程还有一个处于打开状态的管道读句柄未关闭。
MSDN中有一篇关于利用匿名管道来重定向子进程标准句柄(输入、输出)的文章,并且附有代码 - 。
* 如果看以上两段内容有点飘的话可以参照文章例子里面的ReadFromPipe接口 *
匿名管道的安全和访问权限Windows NT安全机制使你可以控制匿名管道的访问权限。关于Windows NT的安全机制的内容请参照文章。
当 你调用函数创建匿名管道时你可以为管道指定一个安全描述符,这个安全描述控制着管道读、写两端的访问权限。如果你指定了空的(NULL)安全描述符,那么 管道将得到一个默认的安全描述符。管道默认安全描述符里的ACLs来自于管道创建者的主要的(primary)或模拟的(impersonation)令 牌。
为了获取管道的安全描述符,你可以调用GetSecurityInfo函数,而为了改变管道的安全描述符,你可以调用SetSecurityInfo函数。
函数一共返回两个到匿名管道的句柄:一个拥有GENERIC_READ和SYNCHRONIZE权限的读句柄;和一个拥有GENERIC_WRITE 和SYNCHRONIZE权限的写句柄。对命名管道而言GENERIC_READ 和GENERIC_WRITE使用了相同的访问权限映射。
l 对匿名管道而言GENERIC_READ访问权限混合了从管道读取数据、读取管道属性、读取管道扩展属性以及*读取*管道的DACL信息。
l 对匿名管道而言GENERIC_ WRITE访问权限混合了向管道写数据、追加数据、写管道属性、写管道扩展属性以及*读取*管道的DACL信息。
Windows管道系统 - 第二篇
一 个命名管道是一个有名的、用于管道服务端与一个或多个管道客户端进行单路(“One-way”)或双向通讯的管道。一个命名管道的所有实例共享同一个管道 名字,但是每一个实例都有它自己的管道句柄和缓冲区,并为客户/服务端的通讯提供独立的通讯渠道。管道实例的使用可以让多个管道客户端同时使用同一个命名 管道。
任何进程都可以访问命名管道,并接受安全权限的检查,通过命名管道使相关的或不相关的进程之间的通讯变得异常简单!
任何进程都可以扮演服务端和客户端双重角色,这一点使点对点双向通讯成为可能。在这里,管道服务端进程指的是创建命名管道的一端,而管道客户端指的是连接到命名管道某个实例的一端。
命 名管道可以用在为本机或不同计算机(跨网络)的进程之间提供通讯的场合,。如果服务端的服务正在运行,那么所有的命名管道都可以通过网络进行远程访问。如 果你只关注命名管道的本机应用场景,那么你完全可以禁止NT AUTHORITY\NETWORK用户访问该命名管道(通过设置管道的安全描述符)或者用本机RPC通讯机制来作为替代方案。
管道命名每个命名管道都有一个全局惟一的名字以示和其它命名管道的区别。管道服务端在调用函数创建一个或多个命名管道实例时会为管道指定一个名字,而管道客户端当调用CreateFile或函数连接命名管道某个实例时会指定要连接的命名管道的名字。
当在CreateFile、或函数中指定管道的名字时请使用如下命名格式:
其中ServerName域是远程或本地计算机的名字,而管道的名字字符串则是由PipeName域来指定的,它可以包含除了反斜杠以外的所有字符,包括数字和特殊字符,整个管道的名字字符串最长可以有256个字符。注意:管道名字不区分大小写!
Windows Me、98、95: 管道名字不能包含冒号
管道服务端不能在另外一台计算机上创建一个管道(也就是说对于管道服务端而言,它只能创建本机命名管道,远程命名管道是对管道客户端而言的),因此函数必须使用一个用句号代替的ServerName域名,格式如下:
管道服务端经常要传递管道的名字给它的客户端,这样管道客户端才能连接到管道。否则,管道客户端必须在编译时就得知道管道的名字。
命名管道打开模式管道服务端在调用函数创建命名管道时在dwOpenMode参数中指定管道的访问方式、异步(重叠)以及直写(Write-through)模式等信息。管道客户端可以在调用CreateFile函数时指定管道的打开模式。
l 访问模式
设置管道的访问方式相当于指定管道服务端句柄的读写访问,下表列出了可以在CreateNamedPipe函数中指定的访问模式掩码,并列出了与CreateFile函数相对应的访问模式掩码:
访问模式
CreateFile的等价物
PIPE_ACCESS_INBOUND
GENERIC_READ (服务端只读,客户端只写)
PIPE_ACCESS_OUTBOUND
GENERIC_WRITE (服务端只写,客户端只读)
PIPE_ACCESS_DUPLEX
GENERIC_READ | GENERIC_WRITE (服务端和客户端可读、可写)
管道客户端使用CreateFile函数连接到命名管道时必须在dwDesiredAccess参数中指定一个和管道服务端(创建管道时指定的访问模式)相兼容的访问模式。例如,当管道服务端创建管道时指定了PIPE_ACCESS_OUTBOUND访问模式,那么,管道客户端就必须指定GENERIC_READ访问模式。注意:对于所有的管道实例访问模式必须一样!
l 异步(重叠)模式
在异步(重叠)模式中,函数执行漫长的读、写和连接操作时可以立即返回而不会阻塞。这使得线程在后台执行耗时操作的同时可以继续执行其它操作。要指定异步(重叠)模式,请使用FILE_FLAG_OVERLAPPED标志。
CreateFile函数允许管道客户端在dwFlagsAndAttributes参数中使用(FILE_FLAG_OVERLAPPED)标志把管道句柄设置为异步(重叠)模式。
l 直写模式
我
们通过FILE_FLAG_WRITE_THROUGH标志来指定直写模式。这个模式仅仅对字节类型管道(也仅限于管道客户端和管道服务端在不同计算机上
的情况)的写操作产生影响。在直写模式下,那些对命名管道进行写操作的函数不会返回,直到网络上的数据传输完毕,并完整地保存到在远程计算机上的管道缓冲
区中。直写模式对那些要求每一个写操作都要求同步的应用非常有用。
如果直写模式没有打开,系统通过缓冲机制来提高网络操作的效率,缓冲机制使系统将多个写操作合并到单个网络传输任务中,这意味着对于用户的某个写操作可以在系统将数据放入输出缓冲区后就成功返回,而不必等系统真正将数据传输完毕再成功返回。
CreateFile函数允许管道客户端在dwFlagsAndAttributes参数中使用 (FILE_FLAG_WRITE_THROUGH)标志把管道句柄设置为直写模式。但要记住,直写模式的管道句柄一旦创建就不能再更改,并且直写模式对于同一个管道实例,服务端和客户端的句柄可以不同。
客户端管道可以使用函数控制那些直写模式被禁用的管道在传输任务开始之前的字节数和超时时间。
Windows管道系统 - 第三篇
管道服务端在函数中通过dwPipeMode参数来指定管道的类型、读和等待模式,管道客户端也可以对CreateFile函数返回的管道句柄指定这些管道模式。
l 输入模式
> 管道的输入模式确定了数据是如何被写进管道的。数据可以字节流或消息流的方式在管道中传输,管道服务端在调用函数创建管道实例时指定管道输入模式,并且这个输入模式对所有的管道实例都必须相同。
> 要创建一个字节类型管道,请指定PIPE_TYPE_BYTE标志或使用默认值即可。在这种输入模式下,所有数据都是以字节流方式被写进管道的,并且系统不区分不同写操作所写入字节之间的差异(就是所写数据一视同仁,一律都按字节对待)。
> 要创建一个消息类型管道,请指定PIPE_TYPE_MESSAGE标志。系统把每次写操作所写入的字节都当作一个消息单元来处理。在直写模式打开的情况下,系统总是在消息类型管道上完成写操作。
l 读模式
>
管道的读模式确定了数据是如何从管道读出的。管道服务端在调用函数时为管道句柄指定初始的读模式,我们有两种模式可以读取数据:字节读模式和消息读模式。
一个指向字节类型管道的句柄只能用字节读模式,而一个指向消息类型管道的句柄即可以用字节读模式又可以用消息读模式。对于同一个管道实例,服务端和客户端
句柄的读模式可以不同。
> 要创建字节读模式的管道句柄,请指定PIPE_READMODE_BYTE标志。数据作为字节流从管道读出。当读取了管道中所有有效字节或者读到了用户指定数量的字节内容,一次读操作就会成功完成。
> 要创建消息模式的管道句柄,请指定PIPE_READMODE_MESSAGE标志。数据作为消息流从管道读出。*只有*在整个消息被读出的情况下一次读操作才会成功完成!如果指定读取的字节长度小于下一条消息的大小,函数在返回0之前会读取尽可能多的消息内容(GetLastError函数此时返回ERROR_MORE_DATA)。而剩余的消息你可以用另外的读操作取出。
> 对于管道客户端,CreateFile函数返回的管道句柄初始总是字节读模式工作,管道客户端和管道服务端都可以使用函数来改变管道句柄的读模式。
l 等待模式
> 管道句柄的等待模式确定了ReadFile、WriteFile和函数如何处理那些耗时的操作。在阻塞等待模式中,这些函数会无限等待管道另一端的进程完成某个操作,而在非阻塞等待模式下,这些函数可以立即返回,否则需要无限期等待。
> 在管道为空的情况下(即:管道里面没有任何数据)管道句柄的等待模式会对ReadFile操作产生影响。使用阻塞等待(模式的)句柄时,(ReadFile)操作只有在线程写到管道对端的数据变得可用时才会成功完成。如果使用非阻塞等待(模式的)句柄时,(ReadFile)函数立即返回0,并且GetLastError函数返回ERROR_NO_DATA。
> 在管道缓冲区不足的情况下(即:管道被塞满)管道句柄的等待模式会对WriteFile操
作产生影响。使用阻塞等待(模式的)句柄时,只有线程从管道的另一端读取数据以腾出足够空间后写操作才会成功完成。如果使用非阻塞等待(模式的)句柄时,
要么没有写进任何字节(对消息类型管道而言),要么在写入所持缓冲区的所有字节后(对字节类型管道而言),写操作都会立即返回一个*非*0值。
> 在没有客户端连接或等待连接到管道实例的情况下管道句柄的等待模式会对操作产生影响。使用阻塞等待(模式的)句柄时,只有当某个管道客户端调用CreateFile或函数连接到管道实例上,连接操作才会成功返回。如果使用非阻塞等待(模式的)句柄时,连接操作立即返回0,并且GetLastError函数返回ERROR_PIPE_LISTENING。
> 或CreateFile函数创建的命名管道句柄默认都是阻塞等待模式。要想用*非*阻塞等待模式创建管道,管道服务端在调用CreateNamedPipe函数时需要指定PIPE_NOWAIT标志。
> 管道客户端和管道服务端都可以通过调用函数指定PIPE_WAIT或PIPE_NOWAIT标志来改变管道句柄的等待模式。
注意:非阻塞等待模式是为了和“Microsoft® LAN Manager version 保持兼容才被支 持的。这种模式不应该被用来实现重叠I/O的命名管道,而应该使用真正的重叠I/O技术,因为它(重叠I/O技术)使函数在返回后可以在后台运行耗时操作。
> 我能想得到的最简单的管道服务器模型应该是:管道服务端创建一个管道实例,并连接到一个客户端,之后和客户端进行正常通讯,通讯结束后断开与客户端的连 接、关闭管道句柄并终止服务。它虽然简单可是在单服务器和多客户端通讯的场合这种模型却非常常见。一个管道服务器通过“与每个管道客户端先建立连接,然后 再断开连接”的操作序列可以实现用单一的服务端管道实例来和多个管道客户端进行连接的目的,但是这样操作效率会非常低。管道服务端必须创建多个管道实例来 有效地处理多个客户端的并发连接。
> 下面有三个基本模型可以用于多管道实例的服务:
l 为每个管道实例创建一个独立的处理线程。例如MSDN中“多线程管道服务器“例子:
l 在ReadFile、 WriteFile和函数中指定一个OVERLAPPED结构来使用重叠操作。例如MSDN中“使用重叠I/O的命名管道服务器 “例子:
l 为ReadFileEx和WriteFileEx函数指定一个(当操作完成时被系统执行的)完成例程来使用重叠操作。例如MSDN中“使用完成例程的命名管道服务器 “例子:
多线程管道服务器模型相比上面三个模型是最容易编写的一个,因为每个管道实例线程处理与一个单一客户端的通讯,线程之间相互独立,互不干扰。系统为每个线程分配所需的处理器时间。但是每个线程使用系统资源对于一个需要处理大量客户端请求的服务器是不利的。
对一个单线程服务器而言,它更容易协调对多个客户端都产生影响的操作,并且它在保护多个客户端对共享资源的并发访问上面相对容易一些。对一个单线程服务器的挑战就是需要重叠操作的协调为处理客户端的并发需要分配相应的处理器时间。
Windows管道系统 - 第四篇
ReadFile、WriteFile、和 函数可以在命名管道上以同步或异步的方式完成输入和输出操作。当函数以同步方式运行时,函数不会返回直到操作完成为止,这意味着调用线程在完成一个耗时操 作时其执行过程可以无限期阻塞。而当函数以异步方式运行时,即使操作没有完成函数也会立即返回,这使得当调用线程释放出来去完成其它任务的同时可以在后台 执行耗时的操作。
使用异步I/O可以使管道服务端用一个循环来完成如下步骤:
1. 在等待函数(例如:WaitForMultipleObjects)中指定多个事件对象,并等待其中一个事件被设置成信号态。
2. 使用等待函数的返回值来确定是哪个重叠操作完成了。
3. 完成任务,必要时清除完成操作并为管道句柄初始化下次操作,比如:为同一个管道句柄开启另一个重叠操作。
重叠操作使管道并发读写数据、用一个单线程在多个管道句柄上完成并发I/O操作成为可能。它使一个单线程管道服务器处理和多个管道客户端的通讯更加有效。例如,MSDN中的例子:
对于一个管道服务端使用同步操作来和多个(多于一个)客户端进行通讯的情况,管道服务端必须为每个管道客户端创建一个独立的处理线程,例如,MSDN中的例子:
l 打开异步操作
ReadFile、WriteFile、和函数仅仅在你为管道句柄打开重叠模式、并指定一个有效的OVERLAPPED结构指针的情况下才可以完成异步操作。如果OVERLAPPED指针为空(NULL),函数返回值会错误的指出操作已经完成。因此,强烈建议:如果你使用FILE_FLAG_OVERLAPPED标志创建了管道句柄并想实现异步操作,那么,你应该总是指定一个合法有效的OVERLAPPED结构指针!
OVERLAPPED结构中的hEvent成员必须包含一个手动复位(manual-reset)事件对象的句柄。这是一个由CreateEvent函
数创建的同步对象。初始化重叠操作的那个线程使用这个事件对象来确定操作何时完成。当在相同的管道句柄上完成并发操作时,你不应使用管道句柄来进行同步
(也就是说不应该在等待函数中使用管道句柄),这是因为没有办法知道到底是哪个操作的完成导致管道句柄被设置成信号态。在相同的管道句柄完成并发操作的唯
一可靠技术就是为每一个操作都使用一个单独的OVERLAPPED结构和它自己的事件对象。关于事件对象的更多内容请查看MSDN文章:Synchronization
当ReadFile,、WriteFile、和操作以异步方式完成时则会发生下面某种情况:
> 当函数返回时如果操作完成,返回值指示着操作的成功或失败。如果发生了某个错误,返回值是0并且GetLastError函数返回除ERROR_IO_PENDING以外的错误代码。
> 当函数返回时如果操作还未完成,返回值是0并且GetLastError返回ERROR_IO_PENDING。在这种情况下,调用线程必须等到操作完成,调用线程必须接着调用GetOverlappedResult函数来确定结果。
l 使用完成例程
ReadFileEx和WriteFileEx函数提供了另一种重叠I/O的模型。不象重叠的ReadFile和WriteFile函数使用一个事件对象来指示I/O操作完成,这些扩展函数指定一个完成例程,一个完成例程是一个普通函数,当读、写操作完成时这些函数被排队执行。完成例程是不会被执行的,当调用ReadFileEx和WriteFileEx的线程通过调用alertable等待操作函数并指定fAlertable参数为TRUE来开始alertable等待操作时,完成例程才会被执行,否则,完成例程是不会被执行的!在alertable等待操作中,当ReadFileEx和WriteFileEx完成例程被排队执行时,函数总是返回。管道服务端可以使用扩展函数为每个连接到它的客户端完成一系列的读、写操作。序列中的每个读、写操作都指定一个完成例程,并且每个完成例程负责初始化序列中的下一步操作。例如MSDN例子代码:
Windows安全机制使你可以控制对命名管道的访问。关于安全方面的更多信息,请参照MSDN文章:Access-Control Model
当 你调用函数时可以为命名管道指定一个安全描述符(security descriptor),这个安全描述符控制着对命名管道两端(客户端和服务端)的访问权限。如果你指定一个空的安全描述符(NULL),那么命名管道将 获得一个默认的安全描述符,默认的安全描述符内部的ACLs赋予了LocalSystem账户、administrators和所有者对命名管道完全控制 的权限,同时也赋予了Everyone组和匿名(anonymous)账户的读权限。
要获取命名管道的安全描述符可以调用GetSecurityInfo函数。而要改变命名管道的安全描述符,可以调用SetSecurityInfo函数。
当一个线程调用CreateNamedPipe函 数打开指向一个已存在的命名管道服务端的句柄时,系统在返回这个句柄之前会执行一个访问检查,访问检查过程会比较线程的访问令牌和访问权限是否和命名管道 安全描述符里的DACL冲突。除了用户请求的访问权限,DACL必须允许调用线程对命名管道拥有FILE_CREATE_PIPE_INSTANCE访问 权限。
同样当客户端调用CreateFile和函数连接到命名管道客户端时,系统在返回句柄之前也会执行一个访问检查。
函数返回的管道句柄总是有SYNCHRONIZE访问权限,它还有GENERIC_READ(读)、GENERIC_WRITE(写)或GENERIC_READ和GENERIC_WRITE(读和写),但这要取决于管道的打开模式。下表是每种打开模式所对应的访问权限:
打开模式
访问权限
PIPE_ACCESS_DUPLEX (0x00000003)
FILE_GENERIC_READ、FILE_GENERIC_WRITE和SYNCHRONIZE
PIPE_ACCESS_INBOUND (0x00000001)
FILE_GENERIC_READ和SYNCHRONIZE
PIPE_ACCESS_OUTBOUND (0x00000002)
FILE_GENERIC_WRITE和SYNCHRONIZE
FILE_GENERIC_READ访问权限融合了:从管道读取数据、读取管道属性、读取扩展属性以及读取管道的DACL这几种访问权限。
FILE_GENERIC_WRITE访问权限融合了:向管道写入数据、向管道追加数据、写管道属性、写扩展属性以及读取管 道的DACL这几种访问权限。因为FILE_APPEND_DATA和FILE_CREATE_PIPE_INSTANCE有着相同的定义,所 以,FILE_GENERIC_WRITE也有创建管道的权限。为了避免定义上混淆,建议使用单一的、权限明确的权限位来替代 FILE_GENERIC_WRITE。
如果想读或写对象的SACL信息,你可以请求管道的ACCESS_SYSTEM_SECURITY 访问权限。要了解关于ACLs和SACL访问权限的更多信息请查看MSDN文章:Access-Control Lists (ACLs)和SACL Access Right
为了避免远程用户或处在不同终端服务会话中的用户访问命名管道,请在管道的DACL中使用登录用户的SID。登录 用户的SID 一样被用于” run-as”登录(以某个用户身份来运行程序)。这个SID用来保护每个会话对象命名空间。如何在C++中获取登陆用的SID请查看MSDN文 章:Getting the Logon SID in C++
模拟一个命名管道客户端模拟(Impersonation)可以让线程运行在与进程所不同的安全上下文中。模拟可以让服务端线程代表客户端来完成操作,但在客户端的安全上下文限制下来完成,而客户端通常情况只有一些较低级别的访问权限。关于模拟方面的更多信息请查看MSDN文章:Impersonation
命名管道服务端线程可以调用ImpersonateNamedPipeClient函数来模拟一个命名管道客户端应用,例如:命名管道服务端可以提供对数据库或文件系统的访问特权,当管道客户端发送请求到服务端时,服务端模拟这个客户端并试图访问受保护的数据库,基于客户端的安全级别,系统随后授权或禁止服务端的访问。当服务端完成模拟时,可以调用RevertToSelf函数来恢复服务端原有的安全令牌。
当 模拟客户端时,模拟级别(impersonation level)(模拟级别共有四级:SecurityAnonymous、SecurityIdentification、 SecurityImpersonation、SecurityDelegation)确定了服务端可以完成的操作。默认情况下,服务端在 SecurityImpersonation级别进行模拟。然而,当客户端调用CreateFile函数打开到管道客户端的句柄时,客户端可以使用SECURITY_SQOS_PRESENT标志来控制服务端的模拟级别。