
管道实际上是用于进程间通信的共享内存. 创建管道的过程称为管道服务器,连接到管道的过程是管道客户端. 命名管道是一种命名管道,用于管道服务器和一个或多个管道客户端之间的单向或双向通信. 命名管道的所有实例共享相同的管道名称,但是每个实例具有独立的缓存和句柄,并提供用于客户服务通信的单独管道. 使用实例可确保多个管道客户端可以同时使用同一个命名管道.
Microsoft Windows NT,Windows 2000,Windows 95和Windows 98均提供对命名管道的支持(不包括Windows CE),但是仅Windows NT和Windows 2000支持服务器端命名管道技术. 命名管道可以连接在同一计算机上的不同进程之间,或者可以跨网络连接在不同计算机上的不同进程之间. 如果连接中断,双方都可以立即收到断开连接消息. . 命令管道是围绕Windows文件系统设计的一种机制,该机制使用命名管道文件系统(命名管道文件系统,NPFS)接口. 数据的发送和接收还使用文件读取和写入功能ReadFile()和WriteFile()完成. 在设计中,由于命名管道还使用Microsoft网络提供程序(MSNP)重定向器,因此无需涉及基础通信协议的详细信息. 命名管道还充分利用了Windows NT和Windows 2000的内置安全功能,并且通信的安全性相对较好.
每个命名管道都有一个唯一的名称,以区别于系统命名对象列表中的其他命名管道. 管道服务器在调用CreateNamedPipe()函数以创建一个或多个命名管道实例时分配了一个名称. 对于管道客户端,在调用CreateFile()或CallNamedPipe()函数以连接到命名管道实例时指定管道名称. 命名管道的命名约定类似于邮件插槽的命名约定,并且其标识也采用UNC格式: \\ ServerName \ pipe \ PipeName
其中,第一部分\\ ServerName指定服务器的名称,在此服务器上创建了命名管道服务,其字符串部分可以表示为小数点(表示此机器),星号(当前网络字段),域名或真实服务管道名称,长度可以达到256个字符;第二部分\ Pipe是不可更改的硬编码字符串,例如邮筒的\ Mailslot,表示该文件属于NPFS;第三部分PipeName的使用该应用程序可以唯一地定义和标识命名管道的名称,并可以建立多级目录.
当管道服务器端调用CreateNamedPipe时,可以通过dwOpenMode指定管道的访问,重叠和直写模式,并且使用CreateFile时,相应的命名管道客户端可以指定相应的模式. 有关详细信息,请参见: (v = vs.85).aspx
命名管道提供两种基本的通信模式: 字节模式和消息模式. 在CreateNamePipe()中创建命名管道时,可以使用PIPE_TYPE_BYTE和PIPE_TYPE_MESSAGE标志设置dwPipeMode参数. 在字节模式下,信息以连续字节流的形式在客户端和服务器之间流动. 这也意味着对于客户端应用程序和服务器应用程序,不可能确切知道在任何特定时间段内从管道读取或写入了多少字节. 在这种通信模式下,当一方将一定数量的字节写入管道后,无法保证管道上的另一方可以读取相同数量的字节. 对于消息模式,客户端和服务器通过一系列不连续的数据包发送和接收数据. 从管道发送的每条消息都必须作为完整的消息读入.
管道客户端和服务器都可以通过SetNamedPipeHandleState更改管道句柄的读取模式(PIPE_READMODE_MESSAGE,PIPE_READMODE_BYTE)和等待模式(PIPE_NOWAIT,PIPE_WAIT).
管道服务器首次调用CreateNamedPipe()函数时,它使用nMaxInstance参数指定可以同时存在的最大管道实例数. 服务器可以重复调用CreateNamedPipe()函数来创建管道的新实例,直到达到设置的最大实例数. 下面给出了CreateNamedPipe()的函数原型:
HANDLE CreateNamedPipe(
LPCTSTR lpName,//指向管道名称的指针
DWORD dwOpenMode,//管道打开模式
DWORD dwPipeMode,//管道模式
DWORD nMaxInstances,//最大实例数
DWORD nOutBufferSize,//输出缓冲区大小
DWORD nInBufferSize,//输入缓冲区大小
DWORD nDefaultTimeOut,//超时设置
LPSECURITY_ATTRIBUTES lpSecurityAttributes //指向安全属性的指针
);
如果在定义的超时值变为零之前可以使用实例管道,则创建成功并且管道句柄将返回以侦听来自客户端的连接请求. 另一方面,客户端使用功能WaitNamedPipe()来使服务器进程等待来自客户端的实例连接. 如果在超时值变为零之前有可用的连接管道,则该函数将成功返回并通过调用CreateFile()或CallNamedPipe()来调用与服务器的连接. 此时,服务器将接受客户端的连接请求并成功建立连接. 服务器调用以等待客户端建立连接的ConnectNamedPipe()函数也将成功返回.
从调用顺序的角度来看,首先,客户端使服务器的CreateFile()通过WaitNamedPipe()在有限的时间内成功创建实例,然后双方通过ConnectNamedPipe()和CreateFile()成功连接,返回文件后,客户端和服务器即可通信.
建立连接后,客户端和服务器可以通过ReadFile()和WriteFile()并使用获得的管道句柄以文件读写的形式相互交换信息. 当客户端和服务器之间的通信结束时,或者当一方由于某种原因需要断开连接时,客户端将调用CloseFile()函数以关闭打开的管道句柄,然后服务器将调用DisconnectNamedPipe()函数. 当然,服务器也可以通过单方面调用DisconnectNamedPipe()来终止连接. 终止连接后,调用函数CloseHandle()关闭管道.
摘要: 主线程创建一个命名管道实例,并等待命名管道客户端建立连接. 当命名管道客户端建立连接时,管道服务器会创建一个线程来为客户端提供服务.
管道服务器代码摘要:
首先获取主线程的真实句柄值
dwRet = :: DuplicateHandle(GetCurrentProcess(),GetCurrentThread(),GetCurrentProcess(),&hMainThread,0,FALSE,DUPLICATE_SAME_ACCESS);
创建一个退出线程,并将主线程的实际句柄用作参数:
HANDLE hExitThread = reinterpret_cast(_beginthreadex(NULL,uiDefStackSize,ExitThread,hMainThread,0,NULL));
在主循环中,首先通过SleepEx将主循环置于Alertable状态,以便在退出线程中,可以通过QueueUserAPC通知主线程退出,创建命名管道实例,并阻塞等待客户端连接通过CreateNamedPipe:
while(true)
{
dwRet = SleepEx(1,TRUE);
if(dwRet == WAIT_IO_COMPLETION)
{
休息;
}
hPipe = CreateNamedPipe(g_namedpipe_name,
PIPE_ACCESS_DUPLEX,
PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT,
PIPE_UNLIMITED_INSTANCES,
BUFSIZ,
BUFSIZ,

0,
NULL);
if(hPipe == INVALID_HANDLE_VALUE)
{
printf(“创建命名管道失败创建命名管道,错误=%d \ n”,GetLastError());
休息;
}
g_hPipe = hPipe;
//等待客户端连接;如果成功,
//该函数返回一个非零值. 如果功能
//返回零,GetLastError返回ERROR_PIPE_CONNECTED.
bConnected = ConnectNamedPipe(hPipe,NULL)? TRUE: (GetLastError()== ERROR_PIPE_CONNECTED);
if(bConnected)
{
//为此客户端创建一个线程.
hThread = reinterpret_cast(_beginthreadex(NULL,uiDefStackSize,WorkerThread,(LPVOID)hPipe,0,NULL));
如果(hThread == NULL)
{
printf(“ CreateThread失败,错误=%d \ n”,GetLastError());
返回0;
}
其他
{
//分离的线程
CloseHandle(hThread);
}
}
其他
{
//客户端无法连接,因此请关闭管道.
CloseHandle(hPipe);
}
}
退出线程中的循环:
while(true)
{
std :: getline(std :: cin,name);
if(name ==“ quit”)
{
/// @ note: 首先,我们应该取消同步io(connectnamedpipe)函数
CancelSynchronousIo(hMainThread);

/// @ note: 然后我们应该通知主线程退出.
QueueUserAPC(Aroc,hMainThread,NULL);
休息;
}
其他
继续;
}
用户进入quit后,CancelSynchronousIo首先取消所有阻塞的IO操作,然后QueueUserAPC通知主线程退出.
有关详情,请参见(v = vs.85).aspx
摘要: 管道服务器首先创建一个完成端口对象,然后创建多个Pipe实例,将这些实例与完成端口相关联,并通过调用ConnectNamedPipe ReadFile,WriteFile和其他方法传递OVERLAPPED非空对象参数以提交异步请求接口. 通过线程循环中的GetQueuedCompletionStatus获取提交的异步请求的结果.
管道服务器代码摘要:
创建完成的端口:
:: CreateIoCompletionPort(INVALID_HANDLE_VALUE,NULL,NULL,1);
创建一个退出线程. 退出线程收到用户输入的“退出”后,它将通知完成端口线程池通过PostQueuedCompletionStatus退出. 由于完成端口线程池的数量为1,因此只需调用一次即可:
HANDLE hExitThread = reinterpret_cast(_beginthreadex(NULL,uiDefStackSize创建命名管道,ExitThread,NULL,0,NULL));
通知主线程退出:
std :: getline(std :: cin,name);
if(name ==“ quit”)
{
:: PostQueuedCompletionStatus(hIocpPort,0,0,(LPOVERLAPPED)&exitOverlapped);
休息;
}
在main函数中创建一定数量的管道设备对象,并将它们与完成端口相关联,并通过ConnectNamedPipe提交异步客户端连接请求:
对于(DWORD i = 0; i
{
Pipe [i] .hPipeInst = CreateNamedPipe(
lpszPipename,//管道名称
PIPE_ACCESS_DUPLEX | //读/写访问权限
FILE_FLAG_OVERLAPPED,//重叠模式
本文来自电脑杂谈,转载请注明本文网址:
https://www.pc-fly.com/a/jisuanjixue/article-288048-1.html
看看淘宝什么吊样了
煽动反政府情绪