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: ConnectNamedPipepipeServer.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";
}