C# c++ 命名管道连接
C# c++ named pipes connection
我正在尝试使用命名管道将 c# 项目与 c++ 项目连接起来,但 c++ 项目未连接。
ps: .exe 都在同一个文件中
附带问题:我不明白在我的管道名称前使用“\\.\pipe\”。它有什么作用,真的很有必要吗?
这是我的代码,也许你可以发现错误
C# 服务器:
Program.cs
static class Program
{
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
pipeHandler pipe = new pipeHandler();
var proc = new Process();
proc.StartInfo.FileName = "cplpltestpipes.exe";
proc.Start();
pipe.establishConnection();
Application.Run(new Form1(pipe));
}
}
public class pipeHandler
{
private StreamReader re;
private StreamWriter wr;
private NamedPipeServerStream pipeServer;
public void establishConnection()
{
pipeServer = new NamedPipeServerStream("myNamedPipe1");
pipeServer.WaitForConnection();
re = new StreamReader(pipeServer);
wr = new StreamWriter(pipeServer);
}
public void writePipe(string text)
{
wr.Write(text);
}
public string readPipe()
{
if(re.Peek()==-1)
System.Threading.Thread.Sleep(2000);
if (re.Peek() > -1)
{
string s;
s = re.ReadToEnd();
return s;
}
else
return "fail";
}
}
Form1.cs:
public partial class Form1 : Form
{
pipeHandler pipePointer;
public Form1(pipeHandler pipe)
{
pipePointer=pipe;
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
}
private void button1_Click(object sender, EventArgs e)
{
pipePointer.writePipe(textBox1.Text);
textBox2.Text = pipePointer.readPipe();
}
}
c++ 客户端
#define chrSize 16
int main()
{
TCHAR chr[chrSize];
DWORD bytesRead;
HANDLE pipeHandler;
LPTSTR pipeName = TEXT("\\.\pipe\myNamedPipe1");
pipeHandler = CreateFile(
pipeName, // 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
bool flag=false;
while (!flag)
{
flag = ConnectNamedPipe(pipeHandler, NULL);
cout << "trying";
}
ReadFile(
pipeHandler, // pipe handle
chr, // buffer to receive reply
chrSize * sizeof(TCHAR), // size of buffer
&bytesRead, // number of bytes read
NULL); // not overlapped
cout << chr;
LPTSTR pipeMessage = TEXT("message receive");
DWORD bytesToWrite= (lstrlen(pipeMessage) + 1) * sizeof(TCHAR);
DWORD cbWritten;
WriteFile(
pipeHandler, // pipe handle
pipeMessage, // message
bytesToWrite, // message length
&cbWritten, // bytes written
NULL); // not overlapped
CloseHandle(pipeHandler);
}
运行 程序只是在 C#
中给出了这个异常
************** 异常文本 **************
System.InvalidOperationException: 管道尚未连接。
....
....
....
并且在 C++ 中只需要 ps 在控制台中打印 "trying"
调用CreateFile
时CreateFile如何知道字符串myNamedPipe1
表示的对象是管道?它知道是因为名称的前缀是 \ServerName\pipe\
。
在你的情况下 ServerName
可以只是 .
因为这是 "This machine" 的快捷方式,如果你将代码切换到 LPTSTR pipeName = TEXT("\\.\pipe\myNamedPipe1");
它应该开始工作没有其他问题。
您不需要将它放在 C# 代码中,因为 NamedPipeServerStream
class puts it there for you.
编辑: 查看您的代码,您可能希望将 pipeServer = new NamedPipeServerStream("myNamedPipe1");
移动到 pipeHandler
的构造函数,现在您的 C++ 程序可能会启动在服务器启动之前,即使您的名称正确,您仍然可能会遇到错误。
EDIT2: ConnectNamedPipe
是 pipeServer.WaitForConnection();
的 C++ 等效项,如果 C++ 程序是客户端,则不应该这样做。一旦从 CreateFile
获得有效句柄,您就可以开始阅读和写作了
EDIT3: 这是一个示例,说明如何在启动 C++ 应用程序之前重写 C# 应用程序以启动服务器
static class Program
{
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
//The server now gets created here.
pipeHandler pipe = new pipeHandler();
var proc = new Process();
proc.StartInfo.FileName = "cplpltestpipes.exe";
proc.Start();
//The server used to be created here.
pipe.EstablishConnection();
Application.Run(new Form1(pipe));
}
}
public class pipeHandler
{
private StreamReader re;
private StreamWriter wr;
private NamedPipeServerStream pipeServer;
public pipeHandler()
{
//We now create the server in the constructor.
pipeServer = new NamedPipeServerStream("myNamedPipe1");
}
public void establishConnection()
{
pipeServer.WaitForConnection();
re = new StreamReader(pipeServer);
wr = new StreamWriter(pipeServer);
}
...
}
然后在你的C++代码中删除
while (!flag)
{
flag = ConnectNamedPipe(pipeHandler, NULL);
cout << "trying";
}
我正在尝试使用命名管道将 c# 项目与 c++ 项目连接起来,但 c++ 项目未连接。
ps: .exe 都在同一个文件中
附带问题:我不明白在我的管道名称前使用“\\.\pipe\”。它有什么作用,真的很有必要吗?
这是我的代码,也许你可以发现错误
C# 服务器:
Program.cs
static class Program
{
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
pipeHandler pipe = new pipeHandler();
var proc = new Process();
proc.StartInfo.FileName = "cplpltestpipes.exe";
proc.Start();
pipe.establishConnection();
Application.Run(new Form1(pipe));
}
}
public class pipeHandler
{
private StreamReader re;
private StreamWriter wr;
private NamedPipeServerStream pipeServer;
public void establishConnection()
{
pipeServer = new NamedPipeServerStream("myNamedPipe1");
pipeServer.WaitForConnection();
re = new StreamReader(pipeServer);
wr = new StreamWriter(pipeServer);
}
public void writePipe(string text)
{
wr.Write(text);
}
public string readPipe()
{
if(re.Peek()==-1)
System.Threading.Thread.Sleep(2000);
if (re.Peek() > -1)
{
string s;
s = re.ReadToEnd();
return s;
}
else
return "fail";
}
}
Form1.cs:
public partial class Form1 : Form
{
pipeHandler pipePointer;
public Form1(pipeHandler pipe)
{
pipePointer=pipe;
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
}
private void button1_Click(object sender, EventArgs e)
{
pipePointer.writePipe(textBox1.Text);
textBox2.Text = pipePointer.readPipe();
}
}
c++ 客户端
#define chrSize 16
int main()
{
TCHAR chr[chrSize];
DWORD bytesRead;
HANDLE pipeHandler;
LPTSTR pipeName = TEXT("\\.\pipe\myNamedPipe1");
pipeHandler = CreateFile(
pipeName, // 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
bool flag=false;
while (!flag)
{
flag = ConnectNamedPipe(pipeHandler, NULL);
cout << "trying";
}
ReadFile(
pipeHandler, // pipe handle
chr, // buffer to receive reply
chrSize * sizeof(TCHAR), // size of buffer
&bytesRead, // number of bytes read
NULL); // not overlapped
cout << chr;
LPTSTR pipeMessage = TEXT("message receive");
DWORD bytesToWrite= (lstrlen(pipeMessage) + 1) * sizeof(TCHAR);
DWORD cbWritten;
WriteFile(
pipeHandler, // pipe handle
pipeMessage, // message
bytesToWrite, // message length
&cbWritten, // bytes written
NULL); // not overlapped
CloseHandle(pipeHandler);
}
运行 程序只是在 C#
中给出了这个异常************** 异常文本 ************** System.InvalidOperationException: 管道尚未连接。 .... .... ....
并且在 C++ 中只需要 ps 在控制台中打印 "trying"
调用CreateFile
时CreateFile如何知道字符串myNamedPipe1
表示的对象是管道?它知道是因为名称的前缀是 \ServerName\pipe\
。
在你的情况下 ServerName
可以只是 .
因为这是 "This machine" 的快捷方式,如果你将代码切换到 LPTSTR pipeName = TEXT("\\.\pipe\myNamedPipe1");
它应该开始工作没有其他问题。
您不需要将它放在 C# 代码中,因为 NamedPipeServerStream
class puts it there for you.
编辑: 查看您的代码,您可能希望将 pipeServer = new NamedPipeServerStream("myNamedPipe1");
移动到 pipeHandler
的构造函数,现在您的 C++ 程序可能会启动在服务器启动之前,即使您的名称正确,您仍然可能会遇到错误。
EDIT2: ConnectNamedPipe
是 pipeServer.WaitForConnection();
的 C++ 等效项,如果 C++ 程序是客户端,则不应该这样做。一旦从 CreateFile
EDIT3: 这是一个示例,说明如何在启动 C++ 应用程序之前重写 C# 应用程序以启动服务器
static class Program
{
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
//The server now gets created here.
pipeHandler pipe = new pipeHandler();
var proc = new Process();
proc.StartInfo.FileName = "cplpltestpipes.exe";
proc.Start();
//The server used to be created here.
pipe.EstablishConnection();
Application.Run(new Form1(pipe));
}
}
public class pipeHandler
{
private StreamReader re;
private StreamWriter wr;
private NamedPipeServerStream pipeServer;
public pipeHandler()
{
//We now create the server in the constructor.
pipeServer = new NamedPipeServerStream("myNamedPipe1");
}
public void establishConnection()
{
pipeServer.WaitForConnection();
re = new StreamReader(pipeServer);
wr = new StreamWriter(pipeServer);
}
...
}
然后在你的C++代码中删除
while (!flag)
{
flag = ConnectNamedPipe(pipeHandler, NULL);
cout << "trying";
}