您的位置:首页 > 理论基础 > 计算机网络

C#使用命名管道通过网络在进程之间进行通信

2013-08-07 16:15 896 查看
from MSDN

命名管道提供的功能比匿名管道多。 其功能包括通过网络进行全双工通信和多个服务器实例;基于消息的通信;以及客户端模拟,这使得连接进程可在远程服务器上使用其自己的权限集。

下面的示例演示如何使用 NamedPipeServerStream 类创建命名管道。 在此示例中,服务器进程创建了四个线程。 每个线程可以接受一个客户端连接。 连接的客户端进程随后向服务器提供一个文件名。 如果客户端具有足够的权限,服务器进程就会打开文件并将其内容发送回客户端。

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 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 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);
}
}

下面的示例演示使用 NamedPipeClientStream 类的客户端进程。 客户端连接服务器进程并向服务器发送一个文件名。 该示例使用模拟,所以运行客户端应用程序的标识必须具有访问文件的权限。 服务器随后将文件内容发送回客户端。 文件内容随后显示在控制台上。
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 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 processes
private 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 Studio
currentProcessName = 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;
}
}

此示例中的客户端进程和服务器进程预期在同一台计算机上运行,因此提供给 NamedPipeClientStream 对象的服务器名称是 "."。 如果客户端进程和服务器进程位于不同的计算机上,则应该用运行服务器进程的计算机的网络名称来替换 "."。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: