命名管道是进程间通讯的一种常用方式,对于命名管道的介绍可以参考别的资料和书籍,这里推荐一个《VC++下命名管道编程的原理及实现》这篇博文,写得比较清楚。但是都是介绍了阻塞模式的编程,我这里主要是介绍利用命名管道OVERLAPPED方式使用非阻塞模式编程。注:文中使用的方法就是函数的意思。

参考MSDN,服务器端创建命名管道(使用CreateNamedPipe方法),不使用FILE_FLAG_OVERLAPPED模式时,当使用ConnectNamedPipe方法时,服务器端会进入阻塞。我们一般处理会创建一个工作线程,在工作线程中使用命名管道,但是会引入一个问题,当我们的程序退出时,这个工作线程没有办法结束,会阻塞在ConnectNamedPipe方法中。使用OVERLAPPED方式可以很好的解决这个问题。在codeproject上有一篇文章《One use for Overlapped I/O》写的比较好,提出了解决方法,大致的思路用下面的代码表示:

OVERLAPPED  op;
HANDLE      h,
            handleArray[2];
BOOL        bStop = FALSE;

memset(&op, 0, sizeof(op));
handleArray[0] = op.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
handleArray[1] = gbl_hStopEvent;

while (bStop == FALSE)
{
    h = CreateNamedPipe(FILE_FLAG_OVERLAPPED);

ConnectNamedPipe(h, &op);

switch (WaitForMultipleObjects(2, handleArray, FALSE, INFINITE))
    {
    case WAIT_OBJECT_0:
        _beginthread(threadProc, 0, h);
        ResetEvent(handleArray[0]);
        break;

case WAIT_OBJECT_0 + 1:
        CloseHandle(h);
        bStop = TRUE;
        break;
    }
}

CloseHandle(handleArray[0]);
大致的思路是创建2个事件,一个用于退出线程,一个用于OVERLAPPED接受的event事件绑定,在CreateNamedPipe时,
使用FILE_FLAG_OVERLAPPED模式,这样在ConnetNamePipe时,就不会阻塞,会立即返回。然后使用
WaitForMultipleObjects方法等待这两个事件。这样就可以实现退出。
这篇文章提出的思路是对的,但是在解决实现上还需要细化。
首先,对于创建的2个事件,参考MSDN,与OVERLAPPED结构关联的event,要是manual-reset event,同时初始态要为signaled,
也就是要使用参数TRUE(为什么初始态要为signaled,这个后面解释)。另外一个是退出线程的事件。在使用
CreateNamedPipe(FILE_FLAG_OVERLAPPED)(伪码);
使用ConnectNamedPipe(h, &op)后,会立即返回,这个时候一般是返回FALSE,使用GetLastError()会得到
ERROR_IO_PENDING,表示这个请求是悬而未决的。我使用一个BOOL fPendingIO标识来记录所有悬而未决的的请求,
fPendingIO=TRUE。然后使用WaitForMultipleObjects方法等待这2个事件。线程现在就会阻塞在这里,
直到有相关的事件处于signaled态。现在来解释一下为什么开始创建事件时初始态为signaled。按照常理,
WaitForMultipleObjects不会被阻塞,因为其中一个事件的状态为signaled。其实不然,它的状态在
connectNamedPipe(h, &op)后已经改变了。对以OVERLAPPED关联的事件,
当使用OVERLAPPED相关的方法操作后,其状态会可能会改变的,主要基于下面3个原则:
1)当实际操作在函数返回前已经完成,事件的状态不会改变。
2)当函数返回是,实际的操作没有完成,也即是说这个操作是Pending的,这个时候事件会被设置为nonsignaled.
3) 当操作的Pending完成后,事件会被设置为signaled。
有了上面的3条原则,OVERLAPPED关联的事件的状态变化就好理解了。当使用connectNamedPipe(h, &op)方法时,
函数会立即返回,而实际这个操作并没有进行,而是Pending了,所以,event会由signaled变为nonsignaled,
当真正有Client连接时,这个操作才会完成,这个时候,event会由nonsignaled变为signaled。这个时候,
WaitForMultipleObjects会继续执行下去。对于Pending后的操作,一定要使用
GetOverlappedResult方法,判断结果。
上面的原则适用ReadFile, WriteFile, ConnectNamedPipe, 和 TransactNamedPipe等函数。
下面是我的代码,设计思路是利用namedpipe实现2个进程间的通讯,客户端发送3个整数给服务器端。
Server端:
m_hEvents[0] = CreateEvent(NULL,TRUE,TRUE,NULL);   // OVERLPPED‘s event
m_hEvents[1] = CreateEvent(NULL,TRUE,FALSE,NULL);  // exit event
namepipe线程:
NamedPipeWorkThread(LPVOID lParam)
{
TRACE("NamedPipeWorkThread/n");

CServerDlg * pDlg = (CServerDlg*)lParam;
BOOL fSuccess;
OVERLAPPED op;
memset(&op,0,sizeof(op));
op.hEvent = pDlg->m_hEvents[0];

LPTSTR lpszPipename = TEXT(".//pipe//mynamedpipe"); 
HANDLE hPipeInst = CreateNamedPipe( 
lpszPipename,            // pipe name 
PIPE_ACCESS_DUPLEX |     // read/write access 
FILE_FLAG_OVERLAPPED,    // overlapped mode 
PIPE_TYPE_MESSAGE |      // message-type pipe 
PIPE_READMODE_MESSAGE |  // message-read mode 
PIPE_WAIT,               // blocking mode 
1,               // number of instances 
BUFSIZE*sizeof(TCHAR),   // output buffer size 
BUFSIZE*sizeof(TCHAR),   // input buffer size 
PIPE_TIMEOUT,            // client time-out 
NULL);                   // default security attributes

if(hPipeInst == INVALID_HANDLE_VALUE) {
AfxMessageBox("CreateNamedPipe failed with %d./n", GetLastError());
return 0;
}

PT_COLOR  PtColor;
DWORD dwBytesReaded;

BOOL fConnected,fPendingIO = FALSE;
fConnected = ConnectNamedPipe(hPipeInst, &op);

if (fConnected) {
AfxMessageBox("ConnectNamedPipe failed with %d./n", GetLastError()); 
return 0;
}

switch (GetLastError()) { 
// The overlapped connection in progress. 
case ERROR_IO_PENDING: 
fPendingIO = TRUE; 
break;

// Client is already connected, so signal an event.

case ERROR_PIPE_CONNECTED: 
if (SetEvent(op.hEvent)) 
            break;

// If an error occurs during the connect operation... 
default: 
{
AfxMessageBox("ConnectNamedPipe failed with %d./n", GetLastError());
return 0;
}
}

DWORD dwRet;
BYTE btState = 0;
while(1){
DWORD dwResult = WaitForMultipleObjects(2,pDlg->m_hEvents,FALSE,INFINITE);

if(0 == dwResult - WAIT_OBJECT_0){
if(fPendingIO){
fSuccess = GetOverlappedResult( 
hPipeInst, // handle to pipe 
&op, // OVERLAPPED structure 
&dwRet,            // bytes transferred 
FALSE);            // do not wait 
switch(btState){
case CONNECTING_STATE:
if (! fSuccess) {
AfxMessageBox("Error %d./n", GetLastError()); 
return 0;
}
btState = READING_STATE;
break;

case READING_STATE:
if(!fSuccess || dwRet == 0){
DisconnectNamedPipe(hPipeInst);
return 0;
}
TRACE("Read bytes = %d/n",dwRet);
TRACE("nX=%d,nY=%d,nColor=%d/n",PtColor.nX,PtColor.nY,PtColor.nColor);
break;
}
}

fSuccess = ReadFile( hPipeInst,&PtColor, sizeof(PT_COLOR),&dwBytesReaded,&op);
if(fSuccess && dwBytesReaded != 0){
fPendingIO = FALSE;
TRACE("Read bytes = %d/n",dwBytesReaded);
TRACE("nX=%d,nY=%d,nColor=%d/n",PtColor.nX,PtColor.nY,PtColor.nColor);
continue;
}
DWORD dwErr = GetLastError(); 
            if (! fSuccess && (dwErr == ERROR_IO_PENDING)) { 
fPendingIO = TRUE; 
continue; 
            }

}
else{
break;
}

}

DisconnectNamedPipe(hPipeInst);

TRACE("exit NamedPipeWorkThread/n");
return 0;
}
客户端:
typedef struct Tag_Pt_Color{
int nX;
int nY;
int nColor;
}PT_COLOR;
LPTSTR lpszPipename = TEXT(".//pipe//mynamedpipe"); 
m_hPipe = CreateFile( 
lpszPipename,   // pipe name 
GENERIC_READ |  // read and write access 
GENERIC_WRITE, 
0,              // no sharing 
NULL,           // default security attributes
OPEN_EXISTING,  // opens existing pipe 
0,              // default attributes 
NULL);          // no template file

if(INVALID_HANDLE_VALUE == m_hPipe){
AfxMessageBox("Create NamedPipe failed with %d./n");
return;
}

DWORD dwMode = PIPE_READMODE_MESSAGE; 
BOOL fSuccess = SetNamedPipeHandleState( 
m_hPipe,    // pipe handle 
&dwMode,  // new pipe mode 
NULL,     // don't set maximum bytes 
NULL);    // don't set maximum time

if ( ! fSuccess) {
CString strMsg;
strMsg.Format("SetNamedPipeHandleState failed. GLE=%d/n", GetLastError());
AfxMessageBox(strMsg); 
return ;
}
PT_COLOR  ptColor;
ptColor.nX = m_nX;
ptColor.nY = m_nY;
ptColor.nColor = m_nColor;

DWORD dwBytesWritten;
BOOL fSuccess = WriteFile(m_hPipe,&ptColor,sizeof(PT_COLOR),&dwBytesWritten,NULL);

if (!fSuccess) 
{
CString strMsg;
strMsg.Format("WriteFile to pipe failed. GLE=%d/n", GetLastError());

AfxMessageBox(strMsg); 
return ;
}

使用命名管道的OVERLAPPED方式实现非阻塞模式编程相关推荐

  1. 使用命名管道的OVERLAPPED方式实现非阻塞模式编程 .

    命令管道是进程间通讯的一种常用方式,对于命令管道的介绍可以参考别的资料和书籍,这里推荐一个<VC++下命名管道编程的原理及实现>这篇博文,写得比较清楚.但是都是介绍了阻塞模式的编程,我这里 ...

  2. 非阻塞模式WinSock编程入门

    介绍 WinSock是Windows提供的包含了一系列网络编程接口的套接字程序库.在这篇文章中,我们将介绍如何把它的非阻塞模式引入到应用程序中.文章中所讨论的通信均为面向连接的通信(TCP),为清晰起 ...

  3. 非阻塞模式WinSock编程入门(Socket关联窗口消息机制)

    本文版权归 CSDN trcj 所有,转载请自觉按如下方式于明显位置标明原作者及出处,以示尊重! 作者:trcj 原文:http://blog.csdn.net/trcj1/archive/2010/ ...

  4. WSAAsyncSelect() 非阻塞模式WinSock

    测试资源地址 所幸的是,WinSock同时提供了非阻塞模式,并提出了几种I/O模型.最常见的I/O模型有select模型.WSAAsyncSelect模型及 WSAEventSelect模型,下面选择 ...

  5. 字符串缓冲区太小怎么解决_epoll的两种模式 ET和LT printf的缓冲区问题 边缘非阻塞模式...

    学习于:https://www.bilibili.com/video/av44660437/?p=9 前文:何柄融:多路复用I/O select poll epoll 何柄融:select poll ...

  6. [转]Socket的阻塞模式和非阻塞模式

    http://blog.csdn.net/VCSockets/ 阻塞模式 Windows套接字在阻塞和非阻塞两种模式下执行I/O操作.在阻塞模式下,在I/O操作完成前,执行的操作函数一直等候而不会立即 ...

  7. Java中如何使用非阻塞异步编程——CompletableFuture

    分享一波:程序员赚外快-必看的巅峰干货 对于Node开发者来说,非阻塞异步编程是他们引以为傲的地方.而在JDK8中,也引入了非阻塞异步编程的概念.所谓非阻塞异步编程,就是一种不需要等待返回结果的多线程 ...

  8. Qt:Qt实现Winsock网络编程—非阻塞模式下的简单远程控制的开发(WSAAsyncSelect)

    Qt实现Winsock网络编程-非阻塞模式下的简单远程控制的开发(WSAAsyncSelect) 前言 这边博客应该是 Qt实现Winsock网络编程-TCP服务端和客户端通信(多线程) 的姐妹篇,上 ...

  9. 转:PHP中实现非阻塞模式

    原文来自于:http://blog.csdn.net/linvo/article/details/5466046 程序非阻塞模式,这里也可以理解成并发.而并发又暂且可以分为网络请求并发 和本地并发 . ...

最新文章

  1. 论一名项目经理的能力素养
  2. python基础之day1
  3. mvc EF 从数据库更新实体,添加视图实体时添加不上的问题
  4. Lambda,会序列化吗?
  5. Spring Http Invoker使用简介
  6. 字符串类型日期时间转换为Date类型解析转换异常java.text.ParseException: Unparseable date: “2019-09-27T18:31:31+08:00”
  7. 第5讲:VUE3工程中实现页面加载中效果和页面切换动画效果。
  8. 通过bat文件批量判断url地址的状态
  9. elasticsearch 常见的概念
  10. 【数据库系统】C#窗体应用显示用户sa登录失败
  11. NLP-文本处理:英文文本挖掘预处理流程总结
  12. python爬取豆瓣电影top250_python3爬取豆瓣top250电影
  13. Ralink SDK相关指令总结
  14. 【android】项目案例(一)之超级课程表
  15. 购买新款macbook pro,现在买还是等双十一?
  16. unity之跳一跳(完整版)
  17. Python AIML搭建聊天机器人(附遇到的问题及解决)
  18. 原生JS利用XMLHttpRequest实现Get和Post请求
  19. [资料分享] 深受电子工程师喜爱的电路资料大合集
  20. hdoj2549 壮志难酬

热门文章

  1. Excel爬虫--------------起点回归
  2. 同一个编译脚本下 arm 交叉编译 生成文件大小不一致的问题分析
  3. Ask, Attend and Answer: Exploring Question-Guided Spatial Attention for Visual Question Answering
  4. ROS学习(22)TF变换
  5. 党员管理系统 spring boot
  6. 随笔:写软件,应该有点专业精神
  7. 听说你不知道如何监控 Node 服务的内存?
  8. 20230107英语学习
  9. 如何哄你的女朋友开心?
  10. PathFileExists()函数使用连接错误解决办法