Named Pipes

A named pipe is a named, one-way or duplex pipe for communication between the pipe server and one or more pipe clients. All instances of a named pipe share the same pipe name, but each instance has its own buffers and handles, and provides a separate conduit for client/server communication. The use of instances enables multiple pipe clients to use the same named pipe simultaneously.

Any process can access named pipes, subject to security checks, making named pipes an easy form of communication between related or unrelated processes.

Any process can act as both a server and a client, making peer-to-peer communication possible. As used here, the term pipe server refers to a process that creates a named pipe, and the term pipe client refers to a process that connects to an instance of a named pipe.

Named pipes can be used to provide communication between processes on the same computer or between processes on different computers across a network. If the server service is running, all named pipes are accessible remotely. If you intend to use a named pipe locally only, deny access to NT AUTHORITY/NETWORK or switch to local RPC.

For more information, see the following topics:

 

Pipe Names

Each named pipe has a unique name that distinguishes it from other named pipes in the system's list of named objects. A pipe server specifies a name for the pipe when it calls the CreateNamedPipe function to create one or more instances of a named pipe. Pipe clients specify the pipe name when they call the CreateFile or CallNamedPipe function to connect to an instance of the named pipe.

Use the following form when specifying the name of a pipe in the CreateFile, WaitNamedPipe, or CallNamedPipe function:

//ServerName/pipe/PipeName

where ServerName is either the name of a remote computer or a period, to specify the local computer. The pipe name string specified by PipeName can include any character other than a backslash, including numbers and special characters. The entire pipe name string can be up to 256 characters long. Pipe names are not case-sensitive.

The pipe server cannot create a pipe on another computer, so CreateNamedPipe must use a period for the server name, as shown in the following example.

//./pipe/PipeName

A pipe server often passes the pipe name to its pipe clients so they can connect to the pipe. Otherwise, the clients must know the pipe name at compile time.


Named Pipe Open Modes

The pipe server specifies the pipe access, overlap, and write-through modes in the dwOpenMode parameter of the CreateNamedPipe function. The pipe clients can specify these open modes for their pipe handles using the CreateFile function.

Access Mode

Setting the pipe access mode is equivalent to specifying read or write access associated with the pipe server's handles. The following table shows the equivalent generic access right for each access mode you can specify with CreateNamedPipe.

Access modeEquivalent generic access right
PIPE_ACCESS_INBOUNDGENERIC_READ
PIPE_ACCESS_OUTBOUNDGENERIC_WRITE
PIPE_ACCESS_DUPLEXGENERIC_READ | GENERIC_WRITE

If the pipe server creates a pipe with PIPE_ACCESS_INBOUND, the pipe is read-only for the pipe server and write-only for the pipe client. If the pipe server creates a pipe with PIPE_ACCESS_OUTBOUND, the pipe is write-only for the pipe server and read-only for the pipe client. A pipe created with PIPE_ACCESS_DUPLEX is read/write for both the pipe server and the pipe client.

Pipe clients using CreateFile to connect to a named pipe must specify an access right in the dwDesiredAccess parameter that is compatible with the access mode specified by the pipe server. For example, a client must specify GENERIC_READ access to open a handle for a pipe that the pipe server created with PIPE_ACCESS_OUTBOUND. The access modes must be the same for all instances of a pipe.

To read pipe attributes such as the read mode or blocking mode, the pipe handle must have the FILE_READ_ATTRIBUTES access right; to write pipe attributes, the pipe handle must have the FILE_WRITE_ATTRIBUTES access right. These access rights can be combined with the generic access right that is appropriate for the pipe: GENERIC_READ with FILE_WRITE_ATTRIBUTES for a read-only pipe, or GENERIC_WRITE with FILE_READ_ATTRIBUTES for a write-only pipe. Restricting access rights in this way provides better security for the pipe.

Overlapped Mode

In overlapped mode, functions performing lengthy read, write, and connect operations can return immediately. This enables the thread to perform other operations while a time-consuming operation is executing in the background. To specify overlapped mode, use the FILE_FLAG_OVERLAPPED flag. For more information, see Synchronous and Overlapped Input and Output.

The CreateFile function allows the pipe client to set overlapped mode (FILE_FLAG_OVERLAPPED) for its pipe handles using the dwFlagsAndAttributes parameter.

Write-Through Mode

Specify write-through mode with FILE_FLAG_WRITE_THROUGH. This mode affects only write operations to byte-type pipes between pipe clients and pipe servers on different computers. In write-through mode, the functions that write to a named pipe do not return until the data is transmitted across the network and into the pipe's buffer on the remote computer. Write-through mode is useful for applications that require synchronization for every write operation.

If write-through mode is not enabled, the system enhances the efficiency of network operations by buffering data until a minimum number of bytes have accumulated or until a maximum time period has elapsed. Buffering enables the system to combine multiple write operations into a single network transmission. This means that a write operation can be successfully completed after the system puts the data in the outbound buffer, but before the system transmits it across the network.

The CreateFile function allows the pipe client to set write-through mode (FILE_FLAG_WRITE_THROUGH) for its pipe handles using the dwFlagsAndAttributes parameter. The write-through mode of a pipe handle cannot be changed after the pipe handle has been created. The write-through mode can be different for server and client handles to the same pipe instance.

A pipe client can use the SetNamedPipeHandleState function to control the number of bytes and the time-out period before transmission for a pipe on which write-through mode is disabled. For a read-only pipe, the pipe handle must be opened with the GENERIC_READ and FILE_WRITE_ATTRIBUTES access rights.

 

Named Pipe Type, Read, and Wait Modes

The pipe server specifies the pipe type mode, read mode, and wait mode in the dwPipeMode parameter of the CreateNamedPipe function. Pipe clients can specify these pipe modes for their pipe handles using the CreateFile function.

Type Mode

The type mode of a pipe determines how data is written to a named pipe. Data can be transmitted through a named pipe as either a stream of bytes or as a stream of messages. The pipe server specifies the pipe type when calling CreateNamedPipe to create an instance of a named pipe. The type modes must be the same for all instances of a pipe.

To create a byte-type pipe, specify PIPE_TYPE_BYTE or use the default value. The data is written to the pipe as a stream of bytes, and the system does not differentiate between the bytes written in different write operations.

To create a message-type pipe, specify PIPE_TYPE_MESSAGE. The system treats the bytes written in each write operation to the pipe as a message unit. The system always performs write operations on message-type pipes as if write-through mode were enabled.

Read Mode

The read mode of a pipe determines how data is read from a named pipe. The pipe server specifies the initial read mode for a pipe handle when calling CreateNamedPipe. Data can be read in byte-read mode or message-read mode. A handle to a byte-type pipe can be in byte-read mode only. A handle to a message-type pipe can be in either byte-read or message-read mode. For a message-type pipe, the read mode can be different for server and client handles to the same pipe instance.

To create the pipe handle in byte-read mode, specify PIPE_READMODE_BYTE or use the default value. Data is read from the pipe as a stream of bytes. A read operation is completed successfully when all available bytes in the pipe are read or when the specified number of bytes is read.

To create the pipe handle in message-read mode, specify PIPE_READMODE_MESSAGE. Data is read from the pipe as a stream of messages. A read operation is completed successfully only when the entire message is read. If the specified number of bytes to read is less than the size of the next message, the function reads as much of the message as possible before returning zero (the GetLastError function returns ERROR_MORE_DATA). The remainder of the message can be read using another read operation.

For a pipe client, a pipe handle returned by CreateFile is always in byte-read mode initially. Both pipe clients and pipe servers can use the SetNamedPipeHandleState function to change the read mode of a pipe handle. The pipe handle must have the FILE_WRITE_ATTRIBUTES access right.

Wait Mode

The wait mode of a pipe handle determines how the ReadFile, WriteFile, and ConnectNamedPipe functions handle lengthy operations. In blocking-wait mode, the functions wait indefinitely for a process on the other end of the pipe to complete an operation. In nonblocking-wait mode, the functions return immediately in situations that would otherwise require an indefinite wait.

A ReadFile operation is affected by the wait mode of a pipe handle when the pipe is empty. With a blocking-wait handle, the operation is not completed successfully until data is available from a thread writing to the other end of the pipe. Using a nonblocking-wait handle, the function returns zero immediately, and the GetLastError function returns ERROR_NO_DATA.

A WriteFile operation is affected by the wait mode of a pipe handle when there is insufficient space in the pipe's buffer. With a blocking-wait handle, the write operation cannot succeed until sufficient space is created in the buffer by a thread reading from the other end of the pipe. With a nonblocking-wait handle, the write operation returns a nonzero value immediately, without writing any bytes (for a message-type pipe) or after writing as many bytes as the buffer holds (for a byte-type pipe).

A ConnectNamedPipe operation is affected by the wait mode of a pipe handle when there is no client connected or waiting to connect to the pipe instance. With a blocking-wait handle, the connect operation does not succeed until a pipe client connects to the pipe instance by calling either the CreateFile or CallNamedPipe function. With a nonblocking-wait handle, the connect operation returns zero immediately, and the GetLastError function returns ERROR_PIPE_LISTENING.

By default, all named pipe handles returned by the CreateNamedPipe or CreateFile function are created with blocking-wait mode enabled. To create the pipe in nonblocking-wait mode, the pipe server specifies PIPE_NOWAIT when calling CreateNamedPipe.

Both pipe clients and pipe servers can change a pipe handle's wait mode by specifying either PIPE_WAIT or PIPE_NOWAIT in a call to the SetNamedPipeHandleState function.

Note  The nonblocking-wait mode is supported for compatibility with Microsoft LAN Manager version 2.0. This mode should not be used to achieve overlapped input and output (I/O) with named pipes. Overlapped I/O should be used instead, because it enables time-consuming operations to run in the background after the function returns. For more information about overlapped I/O, see Synchronous and Overlapped Input and Output.

 

Named Pipe Instances

The simplest pipe server creates a single instance of a pipe, connects to a single client, communicates with the client, disconnects from the client, closes the pipe handle, and terminates. However, it is more common for a pipe server to communicate with multiple pipe clients. A pipe server could use a single pipe instance to connect with multiple pipe clients by connecting to and disconnecting from each client in sequence, but performance would be poor. The pipe server must create multiple pipe instances to efficiently handle multiple clients simultaneously.

There are three basic strategies for servicing multiple pipe instances.

 

The multithreaded pipe server is easiest to write, because the thread for each instance handles communications for a single pipe client. The system allocates processor time to each thread as needed. But each thread uses system resources, which is a disadvantage for a pipe server that handles a large number of clients.

With a single-threaded server, it is easier to coordinate operations that affect multiple clients, and it is easier to protect shared resources from simultaneous access by multiple clients. The challenge of a single-threaded server is that it requires coordination of overlapped operations to allocate processor time for handling the simultaneous needs of clients.

 

Named Pipe Operations

The first time the pipe server calls the CreateNamedPipe function, it uses the nMaxInstances parameter to specify the maximum number of instances of the pipe that can exist simultaneously. The server can call CreateNamedPipe repeatedly to create additional instances of the pipe, as long as it does not exceed the maximum number of instances. If the function succeeds, each call returns a handle to the server end of a named pipe instance.

As soon as the pipe server creates a pipe instance, a pipe client can connect to it by calling the CreateFile or CallNamedPipe function. If a pipe instance is available, CreateFile returns a handle to the client end of the pipe instance. If no instances of the pipe are available, a pipe client can use the WaitNamedPipe function to wait until a pipe becomes available.

A pipe server can determine when a pipe client is connected to a pipe instance by calling the ConnectNamedPipe function. If the pipe handle is in blocking-wait mode, ConnectNamedPipe does not return until a client is connected.

Pipe clients and servers can call one of several functions — in addition to CallNamedPipe— to read from and write to a named pipe. The behavior of these functions depends on the type of pipe and the modes in effect for the specified pipe handle, as follows:

 

  • The ReadFile and WriteFile functions can be used with either byte-type or message-type pipes.
  • The ReadFileEx and WriteFileEx functions can be used with either byte-type or message-type pipes if the pipe handle was opened for overlapped operations.
  • The PeekNamedPipe function can be used to read without removing the contents of either a byte-type pipe or a message-type pipe. PeekNamedPipe can also return additional information about the pipe instance.
  • The TransactNamedPipe function can be used with message-type duplex pipes if the pipe handle to the calling process is set to message-read mode. The function writes a request message and reads a reply message in a single operation, enhancing network performance.

The pipe server should not perform a blocking read operation until the pipe client has started. Otherwise, a race condition can occur. This typically occurs when initialization code, such as that of the C run-time library, needs to lock and examine inherited handles.

When a client and server finish using a pipe instance, the server should first call the FlushFileBuffers function, to ensure that all bytes or messages written to the pipe are read by the client. FlushFileBuffers does not return until the client has read all data from the pipe. The server then calls the DisconnectNamedPipe function to close the connection to the pipe client. This function makes the client's handle invalid, if it has not already been closed. Any unread data in the pipe is discarded. After the client is disconnected, the server calls the CloseHandle function to close its handle to the pipe instance. Alternatively, the server can use ConnectNamedPipe to enable a new client to connect to this instance of the pipe.

A process can retrieve information about a named pipe by calling the GetNamedPipeInfo function, which returns the type of the pipe, the size of the input and output buffers, and the maximum number of pipe instances that can be created. The GetNamedPipeHandleState function reports on the read and wait modes of a pipe handle, the current number of pipe instances, and additional information for pipes that communicate over a network. The SetNamedPipeHandleState function sets the read mode and wait modes of a pipe handle. For pipe clients communicating with a remote server, the function also controls the maximum number of bytes to collect or the maximum time to wait before transmitting a message (assuming the client's handle was not opened with write-through mode enabled).


Synchronous and Overlapped Pipe I/O

The ReadFile, WriteFile, TransactNamedPipe, and ConnectNamedPipe functions can perform input and output operations on a pipe either synchronously or asynchronously. When a function runs synchronously, it does not return until the operation it is performing is completed. This means that the execution of the calling thread can be blocked for an indefinite period while it waits for a time-consuming operation to be completed. When a function runs asynchronously, it returns immediately, even if the operation has not been completed. This enables a time-consuming operation to be executed in the background while the calling thread is free to perform other tasks.

Using asynchronous I/O enables a pipe server to use a loop that performs the following steps:

  1. Specify multiple event objects in a call to the wait function, and wait for one of the objects to be set to the signaled state.
  2. Use the wait function's return value to determine which overlapped operation has finished.
  3. Perform the tasks necessary to clean up the completed operation and initiate the next operation for that pipe handle. This can involve starting another overlapped operation for the same pipe handle.

Overlapped operations make it possible for one pipe to read and write data simultaneously and for a single thread to perform simultaneous I/O operations on multiple pipe handles. This enables a single-threaded pipe server to handle communications with multiple pipe clients efficiently. For an example, see Named Pipe Server Using Overlapped I/O.

For a pipe server to use synchronous operations to communicate with more than one client, it must create a separate thread for each pipe client so that one or more threads can run while other threads are waiting. For an example of a multithreaded pipe server that uses synchronous operations, see Multithreaded Pipe Server.

Enabling Asynchronous Operation

The ReadFile, WriteFile, TransactNamedPipe, and ConnectNamedPipe functions can be performed asynchronously only if you enable overlapped mode for the specified pipe handle and specify a valid pointer to an OVERLAPPED structure. If the OVERLAPPED pointer is NULL, the function return value can incorrectly indicate that the operation has been completed. Therefore, it is strongly recommended that if you create a handle with FILE_FLAG_OVERLAPPED and want asynchronous behavior, you should always specify a valid OVERLAPPED structure.

The hEvent member of the specified OVERLAPPED structure must contain a handle to a manual-reset event object. This is a synchronization object created by the CreateEvent function. The thread that initiates the overlapped operation uses the event object to determine when the operation has finished. You should not use the pipe handle for synchronization when performing simultaneous operations on the same handle because there is no way of knowing which operation's completion caused the pipe handle to be signaled. The only reliable technique for performing simultaneous operations on the same pipe handle is to use a separate OVERLAPPED structure with its own event object for each operation. For more information about event objects, see Synchronization.

When ReadFile, WriteFile, TransactNamedPipe, and ConnectNamedPipe operations are performed asynchronously, one of the following occurs:

 

  • If the operation is complete when the function returns, the return value indicates the success or failure of the operation. If an error occurs, the return value is zero and the GetLastError function returns something other than ERROR_IO_PENDING.
  • If the operation has not finished when the function returns, the return value is zero and GetLastError returns ERROR_IO_PENDING. In this case, the calling thread must wait until the operation has finished. The calling thread must then call the GetOverlappedResult function to determine the results.
Using Completion Routines

The ReadFileEx and WriteFileEx functions provide another form of overlapped I/O. Unlike the overlapped ReadFile and WriteFile functions, which use an event object to signal completion, the extended functions specify a completion routine. A completion routine is a function that is queued for execution when the read or write operation is finished. The completion routine is not executed until the thread that called ReadFileEx and WriteFileEx starts an alertable wait operation by calling one of the alertable wait functions with the fAlertable parameter set to TRUE. In an alertable wait operation, the functions also return when a ReadFileEx or WriteFileEx completion routine is queued for execution. A pipe server can use the extended functions to perform a sequence of read and write operations for each client that connects to it. Each read or write operation in the sequence specifies a completion routine, and each completion routine initiates the next step in the sequence. For an example, see Named Pipe Server Using Completion Routines.


Named Pipe Security and Access Rights

Windows security enables you to control access to named pipes. For more information about security, see Access-Control Model.

You can specify a security descriptor for a named pipe when you call the CreateNamedPipe function. The security descriptor controls access to both client and server ends of the named pipe. If you specify NULL, the named pipe gets a default security descriptor. The ACLs in the default security descriptor for a named pipe grant full control to the LocalSystem account, administrators, and the creator owner. They also grant read access to members of the Everyone group and the anonymous account.

To retrieve a named pipe's security descriptor, call the GetSecurityInfo function. To change the security descriptor of a named pipe, call the SetSecurityInfo function.

When a thread calls CreateNamedPipe to open a handle to the server end of an existing named pipe, the system performs an access check before returning the handle. The access check compares the thread's access token and the requested access rights against the DACL in the named pipe's security descriptor. In addition to the requested access rights, the DACL must allow the calling thread FILE_CREATE_PIPE_INSTANCE access to the named pipe.

Similarly, when a client calls the CreateFile or CallNamedPipe function to connect to the client end of a named pipe, the system performs an access check before granting access to the client.

The handle returned by the CreateNamedPipe function always has SYNCHRONIZE access. It also has GENERIC_READ, GENERIC_WRITE, or both, depending on the open mode of the pipe. The following are the access rights for each open mode.

Open modeAccess rights
PIPE_ACCESS_DUPLEX (0x00000003)FILE_GENERIC_READ, FILE_GENERIC_WRITE, and SYNCHRONIZE
PIPE_ACCESS_INBOUND (0x00000001)FILE_GENERIC_READ and SYNCHRONIZE
PIPE_ACCESS_OUTBOUND (0x00000002)FILE_GENERIC_WRITE and SYNCHRONIZE

FILE_GENERIC_READ access for a named pipe combines the rights to read data from the pipe, read pipe attributes, read extended attributes, and read the pipe's DACL.

FILE_GENERIC_WRITE access for a named pipe combines the rights to write data to the pipe, append data to it, write pipe attributes, write extended attributes, and read the pipe's DACL. Because FILE_APPEND_DATA and FILE_CREATE_PIPE_INSTANCE have the same definition, so FILE_GENERIC_WRITE enables permission to create the pipe. To avoid this problem, use the individual rights instead of using FILE_GENERIC_WRITE.

You can request the ACCESS_SYSTEM_SECURITY access right to a named pipe object if you want to read or write the object's SACL. For more information, see Access-Control Lists (ACLs) and SACL Access Right.

To prevent remote users or users on a different terminal services session from accessing a named pipe, use the logon SID on the DACL for the pipe. The logon SID is used in run-as logons as well; it is the SID used to protect the per-session object namespace. For more information, see Getting the Logon SID in C++.

 

Impersonating a Named Pipe Client

Impersonation is the ability of a thread to execute in a security context different from that of the process that owns the thread. Impersonation enables the server thread to perform actions on behalf of the client, but within the limits of the client's security context. The client typically has some lesser level of access rights. For more information, see Impersonation.

A named pipe server thread can call the ImpersonateNamedPipeClient function to assume the access token of the user connected to the client end of the pipe. For example, a named pipe server can provide access to a database or file system to which the pipe server has privileged access. When a pipe client sends a request to the server, the server impersonates the client and attempts to access the protected database. The system then grants or denies the server's access, based on the security level of the client. When the server is finished, it uses the RevertToSelf function to restore its original security token.

The impersonation level determines the operations the server can perform while impersonating the client. By default, a server impersonates at the SecurityImpersonation impersonation level. However, when the client calls the CreateFile function to open a handle to the client end of the pipe, the client can use the SECURITY_SQOS_PRESENT flag to control the server's impersonation level.

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
当SQL Server无法远程连接时,出现了“Named Pipes provider,错误40”错误。这种错误通常发生在尝试使用SQL Server Management Studio远程连接到SQL Server实例或通过网络应用程序访问SQL Server时。 出现此错误的常见原因是: 1. SQL Server浏览器服务没有启动:SQL Server浏览器服务负责在网络上动态发现和连接到SQL Server实例。确保该服务已启动,以便能够远程连接。 解决方法:在“服务”中找到“SQL Server浏览器”服务,右键单击并选择“启动”。 2. SQL Server实例的网络配置问题:可能存在SQL Server实例配置不正确的问题,导致无法通过命名管道提供程序进行远程连接。 解决方法:在SQL Server配置管理器中,确保TCP/IP协议和命名管道协议已启用,并且配置正确。可以尝试禁用其他协议,只保留TCP/IP和命名管道协议。 3. 防火墙阻止连接:防火墙设置可能会阻止对SQL Server的远程连接。 解决方法:打开适当的防火墙端口,允许进入和离开SQL Server实例的连接。 4. 连接字符串问题:如果是通过.NET应用程序进行连接,可能是连接字符串中的错误导致无法远程连接。 解决方法:检查连接字符串中的服务器名称、用户名、密码和数据库名称等信息是否正确,并确保连接字符串是正确的。 在解决上述问题后,应重新启动SQL Server服务和相关服务,然后尝试远程连接到SQL Server实例。如果问题仍然存在,可以尝试重启服务器并再次进行连接尝试。如果仍然不能解决,可能需要与系统管理员或数据库管理员联系以获取进一步的支持。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值