当前位置: 首页 > 编程日记 > 正文

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

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

转载于:https://www.cnblogs.com/xtfnpgy/p/9285448.html

相关文章:

读梦断代码有感(1)2019.2.05

今天阅读了建民老师推荐的我们软件工程方面的书籍被称为经典的《梦断代码》,虽然只是读了一小部分但还是感受颇深,在我以往的经验看来,我们软件工程专业的书籍应该都是枯燥乏味的代码啊啥的,所以开始我并没有对这本书有多大的期望…

leetcode-25 K个一组反转链表

给你一个链表,每 k 个节点一组进行翻转,请你返回翻转后的链表。 k 是一个正整数,它的值小于或等于链表的长度。 如果节点总数不是 k 的整数倍,那么请将最后剩余的节点保持原有顺序。 示例 : 给定这个链表:1->2-…

自己动手写简单的web应用服务器(4)—利用socket实现文件的下载

直接上源码: 服务器: 1 package download;2 3 import java.io.BufferedInputStream;4 import java.io.BufferedOutputStream;5 import java.io.File;6 import java.io.FileInputStream;7 import java.io.IOException;8 import java.io.OutputStream;9 im…

mysql 数据泵_Oracle 数据泵详解

一、 EXPDP和IMPDP使用说明 Oracle Database 10g引入了最新的数据泵(Data Dump)技术,数据泵导出导入(EXPDP和IMPDP)的作用 1)实现逻辑备份和逻辑恢复. 2)在数据库用户之间移动对象. 3)在数据库之间移动对象 4)实现表空间搬移. 二、数据泵导出导入与传统一、EXPDP和I…

php 使用curl模拟登录discuz以及模拟发帖

<?php$discuz_url http://127.0.0.1/discuz/;//论坛地址$login_url $discuz_url .logging.php?actionlogin;//登录页地址 $post_fields array();//以下两项不需要修改$post_fields[loginfield] username;$post_fields[loginsubmit] true;//用户名和密码&#xff0c;必…

Java数组的初始化

1.动态初始化 数据类型 [] 变量名 new 数据类型 [数组大小]; //数组的动态初始化int [] arr new int [3]; 2.静态初始化 数据类型 [] 变量名 {元素1&#xff0c;元素2.....} //数组的静态初始化int [] arr2 {1,2,3}; 转载于:https://www.cnblogs.com/luguankun/p/1043128…

leetcode-135 分发糖果

题目描述&#xff1a; 老师想给孩子们分发糖果&#xff0c;有 N 个孩子站成了一条直线&#xff0c;老师会根据每个孩子的表现&#xff0c;预先给他们评分。 你需要按照以下要求&#xff0c;帮助老师给这些孩子分发糖果&#xff1a; 每个孩子至少分配到 1 个糖果。 相邻的孩子…

mysql主从数据库含义_(转)Mysql数据库主从心得整理

管理mysql主从有2年多了&#xff0c;管理过200多组mysql主从&#xff0c;几乎涉及到各个版本的主从&#xff0c;本博文属于总结性的&#xff0c;有一部分是摘自网络&#xff0c;大部分是根据自己管理的心得和经验所写&#xff0c;整理了一下&#xff0c;分享给各位同行&#xf…

Const 重载解析

1. Const重载应用场景 首先&#xff0c;对于函数值传递的情况&#xff0c;因为参数传递是通过复制实参创建一个临时变量传递进函数的&#xff0c;函数内只能改变临时变量&#xff0c;但无法改变实参。则这个时候无论加不加const对实参不会产生任何影响。但是在引用或指针传递函…

Ubuntu手机系统会成为第四大手机系统吗

啊蛋评论&#xff1a;先不说哪令人“卧槽”的配置&#xff01;就冲着这双系统。。也要体验一下&#xff01;&#xff08;lz不是给ubuntu写软文的。完全是个人评论。&#xff09; Ubuntu开发商Canonical发布了代号为Edge的智能手机&#xff0c;与其说是发布&#xff0c;倒不如…

codechef ANUCBC(背包)

题目链接: https://www.codechef.com/problems/ANUCBC 按模数进行背包 取模不要直接取&#xff0c;分开写&#xff0c;不然会T #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #include<queue> #include<stack&…

leetcode-386 字典序排数

给定一个整数 n, 返回从 1 到 n 的字典顺序。 例如&#xff0c; 给定 n 13&#xff0c;返回 [1,10,11,12,13,2,3,4,5,6,7,8,9] 。 请尽可能的优化算法的时间复杂度和空间复杂度。 输入的数据 n 小于等于 5,000,000。 根据题目描述&#xff0c;所谓字典顺序&#xff0c;即数…

零售连锁专卖信息化解决方案简介之二

连锁零售它提供了对商业连锁的整体管理&#xff0c;从商品采购开始到面向最终消费者各阶段都可以找到连锁零售的解决方案。连锁零售针对批发、连锁、零售业供应链中不同的业态提出了不同的解决方案。在信息管理系统的层次中隶属于经营决策型&#xff0c;可以帮助企业全面实现DS…

mysql客户端指令_mysql command line client(mysql命令行客户端)

mysql command line client(mysql命令行客户端)(2010-03-24 09:18:38)标签&#xff1a;文化分类&#xff1a;数据库1.输入密码&#xff1a;******2.ues mysql;使用Mysql3.show databases;显示数据库4.use register;使用数据库名为register5.show tables;显示register数据库中的…

StingBuffer

2019独角兽企业重金招聘Python工程师标准>>> 昨天面试问道一题&#xff1a;StringBuffer的底层实现原理是什么&#xff1f;当时想想应该是字符串数组吧&#xff0c;心里也不是有万分把握&#xff0c;面试结果只能等通知了&#xff08;最没戏的结果&#xff09;&…

[HAOI2015]按位或

Description 刚开始你有一个数字0&#xff0c;每一秒钟你会随机选择一个[0,2^n-1]的数字&#xff0c;与你手上的数字进行或&#xff08;c,c的|,pascal的or&#xff09;操作。选择数字i的概率是p[i]。保证0<p[i]<1&#xff0c;Σp[i]1问期望多少秒后&#xff0c;你手上的数…

leetcode-440 字典序的第K小数字

给定整数 n 和 k&#xff0c;找到 1 到 n 中字典序第 k 小的数字。 注意&#xff1a;1 ≤ k ≤ n ≤ 10^9。 示例 : 输入: n: 13 k: 2 输出: 10 解释: 字典序的排列是 [1, 10, 11, 12, 13, 2, 3, 4, 5, 6, 7, 8, 9]&#xff0c;所以第二小的数字是 10。 字典排序数的实现可以…

centos 编译 mysql_Centos编译mysql

下载源码wget http://dev.mysql.com/get/Downloads/MySQL-5.6/mysql-5.6.23.tar.gztar zxvf mysql-5.6.23.tar.gz安装必要的包sudo yum install cmake gcc gcc-c ncurses-devel perl-Data-Dumper cmake ncurses-devel bison autoconf automake zlib* fiex* libxml* libmcrypt* …

java.lang.NoSuchMethodException 错误

报错&#xff1a; Stacktraces java.lang.NoSuchMethodException: com.gssw.action.ProAction.update() java.lang.Class.getMethod(Class.java:1607)org.apache.struts2.interceptor.validation.AnnotationValidationInterceptor.getActionMethod(AnnotationValidationInterce…

tomcat server.xml中文版

为什么80%的码农都做不了架构师&#xff1f;>>> Tomcat Server的结构图 该文件描述了如何启动Tomcat Server <Server> <Listener /> <GlobaNamingResources> </GlobaNamingResources <Service> <Connector /> <Engine> &l…

idea(2)快捷键

CtrlE&#xff1a;最近编辑文件 CtrlJ&#xff1a;自动代码快捷 CtrlN&#xff1a;查找类 CtrlU&#xff1a;大小写转换 CtrlF12&#xff1a;outline Alt1&#xff1a;全屏 AltF1&#xff1a;类定位到左侧目录 AltInsert&#xff1a;万能创建 AltEnter&#xff1a;导入包 CtrlA…

leetcode-102 二叉树的层次遍历

给定一个二叉树&#xff0c;返回其按层次遍历的节点值。 &#xff08;即逐层地&#xff0c;从左到右访问所有节点&#xff09;。 例如: 给定二叉树: [3,9,20,null,null,15,7] 3 / \ 9 20 / \ 15 7 返回其层次遍历结果&#xff1a; [ [3], [9,20], [15,7] ] 方法一&#xff08…

mysql.err日志分析_Mysql日志解析

转载:https://www.cnblogs.com/Fly-Wind/p/5674382.html修改Mysql配置Mysql配置地址为&#xff1a;C:\Program Files (x86)\MySQL\MySQL Server 5.5如果无法修改可以把my.ini拷贝出来&#xff0c;修改完后&#xff0c;再拷贝回去&#xff01;如果配置了Mysql的日志生成路径&…

linux进程间通信-XSI IPC

一 什么是XSI IPC 有三种 IPC我们称作XSI IPC&#xff0c;即消息队列、信号量以及共享存储器&#xff08;共享内存&#xff09;&#xff0c;它们之间有很多相似之处。二 标识符和键 每个内核中的 IPC结构&#xff08;消息队列、信号量或共享内存&#xff09;都用一个非负整数的…

Linux命令之route - 显示和操作IP路由表

转自&#xff1a; http://codingstandards.iteye.com/blog/1125312 用途说明 route命令用于显示和操作IP路由表&#xff08;show / manipulate the IP routing table&#xff09;。要实现两个不同的子网之间的通信&#xff0c;需要一台连接两个网络的路由器&#xff0c;或者同…

ActivityRouter 框架简单实用

ActivityRouter组件化开发小助手用法如下&#xff1a; 跟目录build.gradle dependencies {// activityRouterclasspath com.neenbedankt.gradle.plugins:android-apt:1.8}allprojects {repositories {// ActivityRoutermaven { url "https://jitpack.io" }} } module…

C++ 互斥锁和条件变量实现读写锁

最近的诸多面试经历确实让自己发现内功还不够&#xff0c;还需要持续的学习精进。 实现如下&#xff1a; class RWLock{private:int state;mutex mu;condition_variable cond;public:RWLock():state(0){}void rlock(){mu.lock();while(state < 0){cond.wait(mu);}state;mu…

经常用得到的安卓数据库基类

//创建数据库 public class DBCreate { public static void CreateDatabase(SQLiteDatabase db) { db.beginTransaction(); try { create_NetTaskBuffer(db); insert_SQL(db); db.setTransactionSuccessfu…

mysql5.7 zip安装配置_MySQL5.7的.zip文件的配置安装

由于MySQL5.7之后在javaEE中交互的端口发生了变化&#xff0c;而MySQL官网中5.6、5.7版本64位的只有.zip文件&#xff0c;而.zip文件不像直接下载installer一样可以获取到初始密码&#xff0c;需要通过管理员身份输入命令skip初始密码&#xff0c;所以记录.zip下安装配置过程。…

Linux vsftp配置详解

一.vsftpd说明:LINUX下实现FTP服务的软件很多,最常见的有vsftpd,Wu-ftpd和Proftp等.Red HatEnterprise Linux中默认安装的是vsftpd.访问FTP服务器时需要经过验证,只有经过了FTP服务器的相关验证,用户才能访问和传输文件.vsftpd提供了3种ftp登录形式:(1)anonymous(匿名帐号)使用…