網(wǎng)站優(yōu)化網(wǎng)絡(luò)推廣seo班級(jí)優(yōu)化大師的利和弊
C#.NET 管道為進(jìn)程間通信提供了平臺(tái)。 管道分為兩種類型:
-
匿名管道。
匿名管道在本地計(jì)算機(jī)上提供進(jìn)程間通信。 與命名管道相比,雖然匿名管道需要的開銷更少,但提供的服務(wù)有限。 匿名管道是單向的,不能通過網(wǎng)絡(luò)使用。 僅支持一個(gè)服務(wù)器實(shí)例。 匿名管道可用于線程間通信,也可用于父進(jìn)程和子進(jìn)程之間的通信,因?yàn)楣艿谰浔梢暂p松傳遞給所創(chuàng)建的子進(jìn)程。在 .NET 中,可通過使用?AnonymousPipeServerStream?和?AnonymousPipeClientStream?類來實(shí)現(xiàn)匿名管道。
-
命名管道。
命名管道在管道服務(wù)器和一個(gè)或多個(gè)管道客戶端之間提供進(jìn)程間通信。 命名管道可以是單向的,也可以是雙向的。 它們支持基于消息的通信,并允許多個(gè)客戶端使用相同的管道名稱同時(shí)連接到服務(wù)器進(jìn)程。 命名管道還支持模擬,這樣連接進(jìn)程就可以在遠(yuǎn)程服務(wù)器上使用自己的權(quán)限。在 .NET 中,可通過使用?NamedPipeServerStream?和?NamedPipeClientStream?類來實(shí)現(xiàn)命名管道。
1、如何:使用匿名管道進(jìn)行本地進(jìn)程間通信
匿名管道在本地計(jì)算機(jī)上提供進(jìn)程間通信。 它們提供的功能比命名管道少,但所需要的系統(tǒng)開銷也少。 使用匿名管道,可以在本地計(jì)算機(jī)上更輕松地進(jìn)行進(jìn)程間通信。 不能使用匿名管道進(jìn)行網(wǎng)絡(luò)通信。
若要實(shí)現(xiàn)匿名管道,請使用?AnonymousPipeServerStream?和?AnonymousPipeClientStream?類。
1.1 示例 1
下面的示例展示了如何使用匿名管道將字符串從父進(jìn)程發(fā)送到子進(jìn)程。 本示例在父進(jìn)程中創(chuàng)建一個(gè)?AnonymousPipeServerStream?對象,其?PipeDirection?值為?Out。然后,父進(jìn)程通過使用客戶端句柄創(chuàng)建?AnonymousPipeClientStream?對象來創(chuàng)建子進(jìn)程。 子進(jìn)程的?PipeDirection?值為?In。
接下來,父進(jìn)程將用戶提供的字符串發(fā)送給子進(jìn)程。 字符串在子進(jìn)程的控制臺(tái)中顯示。
下面的示例展示了服務(wù)器進(jìn)程。
using System;
using System.IO;
using System.IO.Pipes;
using System.Diagnostics;class PipeServer
{static void Main(){Process pipeClient = new Process();pipeClient.StartInfo.FileName = "pipeClient.exe";using (AnonymousPipeServerStream pipeServer =new AnonymousPipeServerStream(PipeDirection.Out,HandleInheritability.Inheritable)){Console.WriteLine("[SERVER] Current TransmissionMode: {0}.",pipeServer.TransmissionMode);// Pass the client process a handle to the server.pipeClient.StartInfo.Arguments =pipeServer.GetClientHandleAsString();pipeClient.StartInfo.UseShellExecute = false;pipeClient.Start();pipeServer.DisposeLocalCopyOfClientHandle();try{// Read user input and send that to the client process.using (StreamWriter sw = new StreamWriter(pipeServer)){sw.AutoFlush = true;// Send a 'sync message' and wait for client to receive it.sw.WriteLine("SYNC");pipeServer.WaitForPipeDrain();// Send the console input to the client process.Console.Write("[SERVER] Enter text: ");sw.WriteLine(Console.ReadLine());}}// Catch the IOException that is raised if the pipe is broken// or disconnected.catch (IOException e){Console.WriteLine("[SERVER] Error: {0}", e.Message);}}pipeClient.WaitForExit();pipeClient.Close();Console.WriteLine("[SERVER] Client quit. Server terminating.");}
}
1.2 示例 2
下面的示例展示了客戶端進(jìn)程。 服務(wù)器進(jìn)程啟動(dòng)客戶端進(jìn)程,并為此進(jìn)程提供客戶端句柄。 客戶端代碼生成的可執(zhí)行文件應(yīng)命名為?pipeClient.exe
,并在運(yùn)行服務(wù)器進(jìn)程前復(fù)制到服務(wù)器可執(zhí)行文件所在的相同目錄中。
using System;
using System.IO;
using System.IO.Pipes;class PipeClient
{static void Main(string[] args){if (args.Length > 0){using (PipeStream pipeClient =new AnonymousPipeClientStream(PipeDirection.In, args[0])){Console.WriteLine("[CLIENT] Current TransmissionMode: {0}.",pipeClient.TransmissionMode);using (StreamReader sr = new StreamReader(pipeClient)){// Display the read text to the consolestring temp;// Wait for 'sync message' from the server.do{Console.WriteLine("[CLIENT] Wait for sync...");temp = sr.ReadLine();}while (!temp.StartsWith("SYNC"));// Read the server data and echo to the console.while ((temp = sr.ReadLine()) != null){Console.WriteLine("[CLIENT] Echo: " + temp);}}}}Console.Write("[CLIENT] Press Enter to continue...");Console.ReadLine();}
}
2、如何:使用命名管道進(jìn)行網(wǎng)絡(luò)進(jìn)程間通信
命名管道在管道服務(wù)器和一個(gè)或多個(gè)管道客戶端之間提供進(jìn)程間通信。 它們比匿名管道(用于在本地計(jì)算機(jī)上提供進(jìn)程間的通信)提供更多的功能。 命名管道支持跨網(wǎng)絡(luò)和多個(gè)服務(wù)器實(shí)例的全雙工通信、基于消息的通信以及客戶端模擬,這樣連接進(jìn)程便可在遠(yuǎn)程服務(wù)器上使用自己的權(quán)限集。若要實(shí)現(xiàn)名稱管道,請使用?NamedPipeServerStream?和?NamedPipeClientStream?類。
2.1 示例 1
下面的示例展示了如何使用?NamedPipeServerStream?類創(chuàng)建命名管道。 在此示例中,服務(wù)器進(jìn)程創(chuàng)建四個(gè)線程。 每個(gè)線程都可以接受客戶端連接。 然后,連接的客戶端進(jìn)程向服務(wù)器提供文件名。 如果客戶端擁有足夠的權(quán)限,服務(wù)器進(jìn)程就會(huì)打開文件,并將它的內(nèi)容發(fā)送回客戶端。
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]?.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 connectpipeServer.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 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());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;public StreamString(Stream ioStream){this.ioStream = ioStream;streamEncoding = new UnicodeEncoding();}public string ReadString(){int len = 0;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;}
}// 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);}
}
2.2 示例 2
下面的示例展示了使用?NamedPipeClientStream?類的客戶端進(jìn)程。 客戶端連接到服務(wù)器進(jìn)程,并將文件名發(fā)送到服務(wù)器。 因?yàn)榇耸纠褂媚M,所以運(yùn)行客戶端應(yīng)用的標(biāo)識(shí)必須有權(quán)訪問文件。 然后,服務(wù)器將文件內(nèi)容發(fā)送回客戶端。 接下來,文件內(nèi)容在控制臺(tái)中顯示。
using System;
using System.Diagnostics;
using System.IO;
using System.IO.Pipes;
using System.Security.Principal;
using System.Text;
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"){var pipeClient =new NamedPipeClientStream(".", "testpipe",PipeDirection.InOut, PipeOptions.None,TokenImpersonationLevel.Impersonation);Console.WriteLine("Connecting to server...\n");pipeClient.Connect();var ss = new StreamString(pipeClient);// Validate the server's signature string.if (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(){string currentProcessName = Environment.CommandLine;// Remove extra characters when launched from Visual StudiocurrentProcessName = currentProcessName.Trim('"', ' ');currentProcessName = Path.ChangeExtension(currentProcessName, ".exe");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);int i;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[{plist[j]?.Id}] has exited.");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();var 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;}
}
2.3 可靠編程
因?yàn)榇耸纠械目蛻舳诉M(jìn)程和服務(wù)器進(jìn)程可以在同一臺(tái)計(jì)算機(jī)上運(yùn)行,所以提供給?NamedPipeClientStream?對象的服務(wù)器名稱為?"."
。 如果客戶端進(jìn)程和服務(wù)器進(jìn)程在不同的計(jì)算機(jī)上運(yùn)行,"."
?會(huì)被替換為運(yùn)行服務(wù)器進(jìn)程的計(jì)算機(jī)的網(wǎng)絡(luò)名稱。