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

    here is the example how to implement the auto password in shell script. Echo yourpasswordhere | sudo ...

  2. jquery trigger函数和triggerHandler函数的对照

    一句话的差别就是:trigger will bubbling jQuery events (not default DOM events) and triggerHnadler will not do ...

  3. mysql存储程序

    什么时候会用到存储过程 1.存储过程只在创造时进行编译,以后每次执行存储过程都不需再重新编译,而一般 SQL 语句每执行一次就编译一次,所以使用存储过程可提高数据库执行速度2.当对数据库进行复杂操作时 ...

  4. Revit api 创建族并加载到当前项目

    using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.T ...

  5. Iris分类以及数组reshape想到的

    最近在研究Iris花的逻辑回归分类中看到了如下的代码: from sklearn.linear_model import LogisticRegression X = iris["data& ...

  6. VC++6 调用teststand api的方法

    参考example中的vs2010的例子,创建MFC工程 打开project->setting ,c/c++ tab  cat 选 Proprocessor ->Additional in ...

  7. Zookeeper常用操作命令 ls,ls2,get和stat

    一.启动zk客户端 进入bin目录 cd  /usr/local/zookeeper-3.4.13/bin ./zkCli.sh 出现如下界面,说明已经连接上了 二.ls与ls2命令 1. ls pa ...

  8. EXCEL 将网络图片地址插入为锁定的图片单元格宏

    Sub InsertPic2(ByVal 图片链接 As String, ByVal 插入图片表名 As String, ByVal 插入图片单元格地址 As String) On Error Res ...

  9. 基于redis的乐观锁实践

    redis真是一个分布式应用场景下的好东西,对于我们的应用设计,功劳大大的! 今天要研究的是基于redis的事务机制以及watch指令(CAS)实现乐观锁的过程. 所谓乐观锁,就是利用版本号比较机制, ...

  10. javaweb下载中的一个问题

    如果你发现,response头以及contentType都已经设置没错,但出现浏览器将下载的文件内容显示到新窗口 那么解决方案就是在请求的时候不要产生新的窗口