命令管道是进程间通讯的一种常用方式,对于命令管道的介绍可以参考别的资料和书籍,这里推荐一个《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 eventnamepipe线程: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 ;

 }

本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/jiangdf/archive/2010/06/20/5681487.aspx

使用命名管道的OVERLAPPED方式实现非阻塞模式编程 .的更多相关文章

  1. 看到关于socket非阻塞模式设置方式记录一下。

    关于socket的阻塞与非阻塞模式以及它们之间的优缺点,这已经没什么可言的:我打个很简单的比方,如果你调用socket send函数时: 如果是阻塞模式下: send先比较待发送数据的长度len和套接 ...

  2. TCP同步与异步及阻塞模式,多线程+阻塞模式,非阻塞模式简单介绍

    首先我简单介绍一下同步TCP编程 与异步TCP编程. 在服务端我们通常用一个TcpListener来监听一个IP和端口.客户端来一个请求的连接,在服务端可以用同步的方式来接收,也可以用异步的方式去接收 ...

  3. Socket 阻塞模式和非阻塞模式

    阻塞I/O模型: 简介:进程会一直阻塞,直到数据拷贝 完成 应用程序调用一个IO函数,导致应用程序阻塞,等待数据准备好. 如果数据没有准备好,一直等待….数据准备好了,从内核拷贝到用户空间,IO函数返 ...

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

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

  5. 深入 CSocket 编程之阻塞和非阻塞模式

    有时,花上几个小时阅读.调试.跟踪优秀的源码程序,能够更快地掌握某些技术关键点和精髓.当然,前提是对这些技术大致上有一个了解. 我通过几个采用 CSocket 类编写并基于 Client/Server ...

  6. IO通信模型(二)同步非阻塞模式NIO(NonBlocking IO)

    同步非阻塞模式(NonBlocking IO) 在非阻塞模式中,发出Socket的accept()和read()操作时,如果内核中的数据还没有准备好,那么它并不会阻塞用户进程,而是立刻返回一个信息.也 ...

  7. Socket阻塞模式和非阻塞模式的区别

    简单点说: 阻塞就是干不完不准回来,    非组赛就是你先干,我现看看有其他事没有,完了告诉我一声 我们拿最常用的send和recv两个函数来说吧... 比如你调用send函数发送一定的Byte,在系 ...

  8. thinkphp并发 阻塞模式与非阻塞模式

    结构代码 public function index(){ $fp = fopen("lock.txt", "w+"); if(flock($fp,LOCK_E ...

  9. NIO非阻塞式编程

    /** * NIO非阻塞式编程<p> * 服务端和客户端各自维护一个管理通道的对象,我们称之为selector,该对象能检测一个或多个通道 (channel) 上的事件. * 我们以服务端 ...

随机推荐

  1. S老师 Top-Down RPG Starter Kit 学习

    character creation using UnityEngine; using System.Collections; public class CharacterCreation : Mon ...

  2. 两个int(32位)整数m和n的二进制表达中,有多少个位(bit)不同

    思路:利用&用算加右移的方法来提取二进制中的每一位数,然后进行比较,查看是否相同. #include<stdio.h> #include<stdlib.h> int m ...

  3. MySQL 中的反引号(`):是为了区分 MySql 关键字与普通字符而引入的符号;一般,表名与字段名都使用反引号。

    MySQL 中的反引号(`):是为了区分 MySql 关键字与普通字符而引入的符号:一般,表名与字段名都使用反引号.

  4. TypeScript 之 声明文件的结构

    https://www.tslang.cn/docs/handbook/declaration-files/library-structures.html 模块化库 一些库只能工作在模块加载器的环境下 ...

  5. centos7 pptp 安装

    1  安装 ppp yum install -y ppp 2 安装 pptpd yum install -y pptpd 3 编辑/etc/pptpd.conf 在最后 添加 localip 192. ...

  6. Python 处理JSON数据报错解决办法

    春节期间通过接口爬取携程数据的时候,返回的json字符串通过json.loads加载时报错"ValueError: Invalid control character at: line 1 ...

  7. 负载均衡器 Ribbion

    一.客户端负载均衡器 Ribbon 客户端向服务器如Eureka Server拉取已经注册的服务信息,然后根据负载均衡策略, 直接命中哪一台服务器发送请求. 整个过程在客户端完成,不需要服务器的参与. ...

  8. MinGW与Cygwin的一些杂谈

    引用:http://www.cnblogs.com/fancybit/archive/2012/07/08/2581590.html 首先MingW和cygwin都可以用来跨平台开发.  MinGW是 ...

  9. Linux/Centos下安装部署phantomjs 及使用

    PhantomJS 是一个基于 WebKit 的服务器端 JavaScript API.它全面支持web而不需浏览器支持,其快速,原生支持各种Web标准: DOM 处理, CSS 选择器, JSON, ...

  10. mongodb 慕课网

    ------------------------------------------------mongodb简述------------------------------------------- ...