在学习《CLR via C#》的27.2小节中使用了管道。因此先对管道(pipe)的相关知识进行梳理
Pipe
其在System.IO.Pipes命名空间下,此命名空间内的类主要任务就是完成不同进程之间的通信。其包含了anonymous pipe(匿名管道)和Named pipe(命名管道)。以下内容主要讲述命名管道的相关知识
1、命名管道的本质是一个使用“共享内存”模式的Stream,不同的进程采用CLR规定的规则(即使用Pipe),才可以进行进程间的通信。
以下直接使用代码进行说明。

using System;
using System.IO;
using System.IO.Pipes;  //要引入命名空间
using System.Text;
using System.Threading;public class PipeServer
{private static int numThreads = 4;public static void Main(){int i;Thread[] servers = new Thread[numThreads];Console.WriteLine("\n*** Named pipe server stream with impersonation example ***\n");Console.WriteLine("Waiting for client connect...\n");for (i = 0; i < numThreads; i++){//声明一个处理线程servers[i] = new Thread(ServerThread); //此处应该添加以下代码//servers[i].IsBackground=true;//因为通过Thread创建的线程默认是前台线程,若前台线程会导致一个问题(特别是在UI界面上[例如winform]),造成winform应用程序不终止。因此在使用时要特别注意这点。servers[i].Start();}Thread.Sleep(250);while (i > 0){for (int j = 0; j < numThreads; j++){if (servers[j] != null){if (servers[j].Join(250)){Console.WriteLine("Server thread[{0}] finished.", servers[j].ManagedThreadId);servers[j] = null;i--;    // decrement the thread watch count}}}}Console.WriteLine("\nServer threads exhausted, exiting.");}//线程需要处理的具体内容private static void ServerThread(object data){NamedPipeServerStream pipeServer =new NamedPipeServerStream("testpipe", PipeDirection.InOut, numThreads);int threadId = Thread.CurrentThread.ManagedThreadId;// Wait for a client to connect//此处,服务器上的线程会阻塞,因为要等待客户端的链接。直到有客户端发起链接请求,线程才能继续执行,否则线程阻塞pipeServer.WaitForConnection();Console.WriteLine("Client connected on thread[{0}].", threadId);try{// Read the request from the client. Once the client has// written to the pipe its security token will be available.// StreamString的具体定义参见其定义StreamString ss = new StreamString(pipeServer);// Verify our identity to the connected client using a// string that the client anticipates.ss.WriteString("I am the one true server!");string filename = ss.ReadString();// Read in the contents of the file while impersonating the client.ReadFileToStream fileReader = new ReadFileToStream(ss, filename);// Display the name of the user we are impersonating.Console.WriteLine("Reading file: {0} on thread[{1}] as user: {2}.",filename, threadId, pipeServer.GetImpersonationUserName());//***RunAsClient的具体说明参见代码下方pipeServer.RunAsClient(fileReader.Start);}// Catch the IOException that is raised if the pipe is broken// or disconnected.catch (IOException e){Console.WriteLine("ERROR: {0}", e.Message);}pipeServer.Close();}
}// Defines the data protocol for reading and writing strings on our stream
// 定义数据格式协议
public class StreamString
{private Stream ioStream;private UnicodeEncoding streamEncoding;//本类在创建实例时,会将NamedPipeServerStream传入,因此在本类里面所有的ioStream变量,就是pipeServerStreampublic StreamString(Stream ioStream){this.ioStream = ioStream;streamEncoding = new UnicodeEncoding();}public string ReadString(){int len = 0;//可以地方很好玩,之前一直在想为啥要这么写,是有内部的原因吗?//哈哈,看了WriteString就明白,这就是“原作者”写的玩的//“原作者”想在读取内容的前两位存储内容的长度。只要按照这个规矩,客户端在发送前会将内容的长度写在最前面两位,// 这样服务器端就知道需要创建多大的byte数组,这样就可以避免浪费空间。// 若自己在写demo时,因为知道自己的文件内容,因此可以直接在服务器端定义byte数组的长度len = ioStream.ReadByte() * 256;len += ioStream.ReadByte();byte[] inBuffer = new byte[len];ioStream.Read(inBuffer, 0, len);return streamEncoding.GetString(inBuffer);}public int WriteString(string outString){byte[] outBuffer = streamEncoding.GetBytes(outString);int len = outBuffer.Length;if (len > UInt16.MaxValue){len = (int)UInt16.MaxValue;}//这个地方就解释了ReadString方法中为什么会有先读取两字节的操作了ioStream.WriteByte((byte)(len / 256));ioStream.WriteByte((byte)(len & 255));ioStream.Write(outBuffer, 0, len);ioStream.Flush();return outBuffer.Length + 2;}
}// Contains the method executed in the context of the impersonated user
public class ReadFileToStream
{private string fn;private StreamString ss;public ReadFileToStream(StreamString str, string filename){fn = filename;ss = str;}public void Start(){string contents = File.ReadAllText(fn);ss.WriteString(contents);}
}

RunAsClient方法第一次没明白什么意思。这个方法从字面意思是指:服务器“变身”客户端。通过网上的查询,自己对这个方法的理解如下:当服务器实例(NamedPipeServerStream)调用本方法时,会获取连接到本服务器上的客户端的Token,使得客户端的权限应用到服务器上。换句话说,本方法并不是说服务器端使用某种机制“变身”成客户端,而是客户端的权限授予服务器端,便于服务器对客户端上的文件进行操作。
说明1:以下的场景最为常用。服务器与客户端建立连接后,服务器端需要读取客户端上的文件内容。但此时服务器端并没有读取客户端文件的权限,需要客户端授权。因此,当服务器端调用RunAsClient后,客户端的相关权限就授予了服务器端,服务器就可以对文件进行操作了。从这个层面上讲是相当于客户端(方法中使用了“s)。
说明2:若在同一台电脑上创建了服务器端和客户端,则不使用RunAsClient也不会报错。但若使用远程连接,若不使用RunAsClient而直接使用读取数据的方法则会出现问题。
因此上面的例子中有如下的代码:

//若直接使用如下代码,在本机不会报错,但在远程桌面连接时,会出现异常
// fileReader.Start();
pipeServer.RunAsClient(fileReader.Start);

fileReader.Start的定义如下:

    public void Start(){string contents = File.ReadAllText(fn);ss.WriteString(contents);}

读取客户端的文件内容。因此就需要使用RunAsClient方法,若不使用本方法,则就会报异常。
客户端的代码如下:

using System;
using System.IO;
using System.IO.Pipes;
using System.Text;
using System.Security.Principal;
using System.Diagnostics;
using System.Threading;public class PipeClient
{private static int numClients = 4;public static void Main(string[] Args){if (Args.Length > 0){if (Args[0] == "spawnclient"){NamedPipeClientStream pipeClient =new NamedPipeClientStream(".", "testpipe",PipeDirection.InOut, PipeOptions.None,TokenImpersonationLevel.Impersonation);Console.WriteLine("Connecting to server...\n");pipeClient.Connect();StreamString ss = new StreamString(pipeClient);// Validate the server's signature stringif (ss.ReadString() == "I am the one true server!"){// The client security token is sent with the first write.// Send the name of the file whose contents are returned// by the server.ss.WriteString("c:\\textfile.txt");// Print the file to the screen.Console.Write(ss.ReadString());}else{Console.WriteLine("Server could not be verified.");}pipeClient.Close();// Give the client process some time to display results before exiting.Thread.Sleep(4000);}}else{Console.WriteLine("\n*** Named pipe client stream with impersonation example ***\n");StartClients();}}// Helper function to create pipe client processesprivate static void StartClients(){int i;string currentProcessName = Environment.CommandLine;Process[] plist = new Process[numClients];Console.WriteLine("Spawning client processes...\n");if (currentProcessName.Contains(Environment.CurrentDirectory)){currentProcessName = currentProcessName.Replace(Environment.CurrentDirectory, String.Empty);}// Remove extra characters when launched from Visual StudiocurrentProcessName = currentProcessName.Replace("\\", String.Empty);currentProcessName = currentProcessName.Replace("\"", String.Empty);for (i = 0; i < numClients; i++){// Start 'this' program but spawn a named pipe client.plist[i] = Process.Start(currentProcessName, "spawnclient");}while (i > 0){for (int j = 0; j < numClients; j++){if (plist[j] != null){if (plist[j].HasExited){Console.WriteLine("Client process[{0}] has exited.",plist[j].Id);plist[j] = null;i--;    // decrement the process watch count}else{Thread.Sleep(250);}}}}Console.WriteLine("\nClient processes finished, exiting.");}
}// Defines the data protocol for reading and writing strings on our stream
public class StreamString
{private Stream ioStream;private UnicodeEncoding streamEncoding;public StreamString(Stream ioStream){this.ioStream = ioStream;streamEncoding = new UnicodeEncoding();}public string ReadString(){int len;len = ioStream.ReadByte() * 256;len += ioStream.ReadByte();byte[] inBuffer = new byte[len];ioStream.Read(inBuffer, 0, len);return streamEncoding.GetString(inBuffer);}public int WriteString(string outString){byte[] outBuffer = streamEncoding.GetBytes(outString);int len = outBuffer.Length;if (len > UInt16.MaxValue){len = (int)UInt16.MaxValue;}ioStream.WriteByte((byte)(len / 256));ioStream.WriteByte((byte)(len & 255));ioStream.Write(outBuffer, 0, len);ioStream.Flush();return outBuffer.Length + 2;}
}

以上代码全部复制于MSDN,具体网址如下:MSDN上关于Pipe的使用
小节
在测试命名管道相关的程序中存在这样一个问题。若远程server端设置了用户名/密码,则客户端会报异常,无法连接到服务器端。另外,需要验证一个问题,要连接到server端是否需要将防火墙关闭!此问题需要验证!

参考文献:
1、http://www.cnblogs.com/langu/archive/2013/02/22/2922542.html
2、http://blog.csdn.net/jcx5083761/article/details/7955489
3、MSDN:https://msdn.microsoft.com/zh-cn/library/bb546085.aspx
4、StackOverflow:http://stackoverflow.com/questions/23832090/how-do-you-loaduserpofile-from-within-namepipeserverstream-runasclient
5、CodeProject:http://www.codeproject.com/Articles/125810/A-complete-Impersonation-Demo-in-Csharp-N

《CLR via C#》读书笔记-异步编程(一)相关推荐

  1. Core Java 8 读书笔记-Networking编程

    Core Java 8 读书笔记-Networking编程 作者:老九-技术大黍 原文:Core Java 8th Edition 社交:知乎 公众号:老九学堂(新人有惊喜) 特别声明:原创不易,未经 ...

  2. 剑指offer(第二版)读书笔记以及编程题目python版答案(二)

    剑指offer(第二版)读书笔记以及编程题目python版答案(二) 题目五:青蛙跳台阶 github地址: https://github.com/ciecus/leetcode_answers/tr ...

  3. nodejs笔记-异步编程

    1.函数式编程 1.1高阶函数 函数参数只接受基本数据类型或者对象引用,返回值也是基本数据类型和对象引用. //常规参数传递和返回 function foo(x) {return x; } 复制代码 ...

  4. 小白的第一本python书_读书笔记:编程小白的第一本python入门书

    书名:编程小白的第一本python入门书 作者:侯爵 出版社/出处:图灵社区 年份:2016年 封面: 感想: 本书短小精悍,精华部分在于给编程小白打了鸡血的同时输出了一种"高效学习法的思想 ...

  5. 读书笔记————Python编程快速上手

    学习笔记 文章目录 基础 整型.浮点型和字符串数据类型 字符串连接和复制 变量命名规则 `print()`函数 `input()`函数 `len()`函数 `str() float() int()`函 ...

  6. 读书笔记: Unix编程实践教程

    目录 第1章 Unix系统编程概述 第2章 用户.文件操作与联机帮助:编写who命令 第3章 目录与文件属性:编写ls 第4章 文件系统:编写pwd 第5章 连接控制:学习stty 第6章 为用户编程 ...

  7. 读书笔记:编程小白的第一本python入门书

    书名:编程小白的第一本python入门书 作者:侯爵 出版社/出处:图灵社区 年份:2016年 封面: 感想: 本书短小精悍,精华部分在于给编程小白打了鸡血的同时输出了一种"高效学习法的思想 ...

  8. 读书笔记-OpenCL编程指南 简介

    OpenCL是Open Computing Language(开放语言的缩写).设立OpenCL的目的就是为日益庞大的并行计算市场提供一个开放的.免费的行业标准.它让开发人员能够利用CPU.GPU等计 ...

  9. Linux C编程一站式学习读书笔记——socket编程

    前言 研一的时候写过socket网络编程,研二这一年已经在用php写api都快把之前的基础知识忘干净了,这里回顾一下,主要也是项目里用到了,最近博客好杂乱啊,不过确实是到了关键时刻,各种复习加巩固准备 ...

最新文章

  1. Microsoft Security Essentials 4.1.522.0 RTM
  2. python函数调用追踪_Python函数调用追踪实现代码
  3. vscode更改插件路径_vscode插件分享
  4. Windows NT OS 的技术架构图
  5. 一架无人机加入警队4个月,墨西哥小城犯罪率下降了10%
  6. 文件夹缩写(文件夹空格问题解决)
  7. map的基本操作总结C++
  8. css灯箱放大图片,wordpress插件wordpress文章图片放大灯箱效果插件auto-highslide优化版...
  9. win10自带安全中心关闭方法
  10. matlab 门函数频谱,时域门函数及门函数串的频谱分析
  11. 以面试的方式了解消息中间件MQ与RabbitMQ
  12. 西湖论剑 easyCpp writeup
  13. 华为4g模块测试软件,华为LTE 4G模块ME906E/华为FDD联通模块
  14. matlab 自激振荡,基于Simulink的非线性系统自激振荡的仿真
  15. Android百日程序:绘画程序-画手指路径
  16. Python实现检测字符串是否全为汉字(含生僻字)
  17. mysql即是主键又是外键怎么写_数据库 既是主键又是外键
  18. html在线编辑器合并单元格,Bootstrap实现的表格合并单元格示例
  19. js 中文加密解密
  20. 简易垂直搜索引擎的核心算法总结

热门文章

  1. Spark Sparrow
  2. Python学习:问题 VisibleDeprecationWarning: Creating an ndarray from ragged nested sequences (which is a
  3. 前端复杂表格导出excel,一键导出 Antd Table 看这篇就够了(附源码)
  4. 笔记本电脑进水了怎么办?
  5. [简历杂谈] 想进500强,英文简历全攻略
  6. JZOJ(中山纪念中学) 2018.02.02【NOIP普及组】模拟赛D组
  7. oracle 导出数据expdp的query参数用法
  8. 【翻译一下官方文档】邂逅uniCloud云函数(基础篇)
  9. 如何阅读经济学人的文章
  10. 网上买充电宝怎么选?网上选充电宝的技巧