c#命名管道双向通信

时间:2016-02-20 13:05:42

标签: c# c++ ipc named-pipes

我有两个用c ++和c#编写的程序。我想在它们之间使用命名管道建立双向通信。 C#客户端程序可以连接到由c ++服务器程序创建的命名管道。但是两端都没有收到。

这是c ++部分(服务器):

#include <iostream>
#include <windows.h>
#include <stdlib.h>
#define UNICODE
using namespace std;
HANDLE hnamedPipe = INVALID_HANDLE_VALUE;
BOOL Finished =false;
HANDLE hThread = NULL;
unsigned long __stdcall CS_RcvThr(void * pParam) ;
int main(int argc, char **argv)
{
    hnamedPipe = CreateNamedPipe(
        "\\\\.\\pipe\\vikeyP",
        PIPE_ACCESS_DUPLEX,
        PIPE_TYPE_MESSAGE|
        PIPE_READMODE_MESSAGE|
        PIPE_WAIT,
        PIPE_UNLIMITED_INSTANCES,
        1024,
        1024,
        NMPWAIT_USE_DEFAULT_WAIT,
        NULL);

    if(hnamedPipe == INVALID_HANDLE_VALUE)
    {
        cout << "Failed" << endl;
    }

    while (true)
    {
        cout<< "Waiting for client"<< endl;
        if(!ConnectNamedPipe(hnamedPipe,NULL))
        {
            if(ERROR_PIPE_CONNECTED != GetLastError())
            {
                cout << "FAIL"<< endl;
            }
        }
        else
        {
            cout<<"Connected!"<<endl;
            hThread = CreateThread( NULL, 0, &CS_RcvThr, NULL, 0, NULL);
            if(hThread) cout<<"read thread created"<<endl; else cout<<"cant crat rd thed\n";
            break;
        }
    }

    while(1)
    {
        cout<<"lst loop"<<endl;
        //Send over the message
        char chResponse[] = "hello\n";
        DWORD cbResponse,cbWritten;
        cbResponse = sizeof(chResponse);

        if (!WriteFile(
        hnamedPipe,
        chResponse,
        cbResponse,
        &cbWritten,
        NULL))
        {
            wprintf(L"failiure w/err 0x%08lx\n",GetLastError);
        }
        cout<<"Sent bytes :)" << endl;
        Sleep(10);
    }
}

unsigned long __stdcall CS_RcvThr(void * pParam) {
    BOOL fSuccess; 
    char chBuf[100];
    DWORD dwBytesToWrite = (DWORD)strlen(chBuf);
    DWORD cbRead;
    int i;

    while (1)
    {
        fSuccess =ReadFile( hnamedPipe,chBuf,dwBytesToWrite,&cbRead, NULL); 
        if (fSuccess)
        {
            printf("C++ App: Received %d Bytes : ",cbRead);
            for(i=0;i<cbRead;i++)
                printf("%c",chBuf[i]);
            printf("\n");
        }
        if (! fSuccess && GetLastError() != ERROR_MORE_DATA) 
        {
            printf("Can't Read\n");
            if(Finished)
                break;
        }
    }
}

这是C#部分(客户端):

    private Thread vikeyClientThread;
    public void ThreadStartClient()
    {
        Console.WriteLine("Thread client started ID ={0} name = {1} " ,
        Thread.CurrentThread.ManagedThreadId,Thread.CurrentThread.Name);
        using (NamedPipeClientStream pipeStream = new NamedPipeClientStream(".", "vikeyP"))
        {
            // The connect function will indefinately wait for the pipe to become available
            // If that is not acceptable specify a maximum waiting time (in ms)
            Console.WriteLine("Connecting to ViKEY server...");
            pipeStream.Connect();
            Console.WriteLine("Connected :)");

            //Write from client to server
            StreamWriter sw = new StreamWriter(pipeStream);
            while (true)
            {
                //Read server reply
                StreamReader sr = new StreamReader(pipeStream);
                string temp = "";
                sw.WriteLine(System.DateTime.Now);
                byte[] c = new byte[200];
                temp = sr.ReadLine();  
                pipeStream.Read(c, 0, c.Length);
                Console.WriteLine("RX =:{0}", Encoding.UTF8.GetString(c, 0, c.Length));
                Thread.Sleep(500);
            }
        }
        Console.WriteLine("Vikey pipe Closed");
        Console.WriteLine("Thread with ID ={0} name = {1} is closed.",
        Thread.CurrentThread.ManagedThreadId, Thread.CurrentThread.Name);
    }

1 个答案:

答案 0 :(得分:0)

您已将服务器端设置为消息类型与字节类型。如果要读取任意数量的字节,则需要使用名为pipe的字节类型。

您将流包装在一个StreamReader和一个StreamWriter的2个对象中。不要这样做,只需使用Stream。你试图逐行阅读,也不要这样做。而是发送要读取的字节数,后跟字节。在客户端,您将读取字节数,然后创建一个足够大的缓冲区,然后读取。如果它是文本数据,那么您将使用编码器(可能是ASCII)将其转换回C#字符串。

您的while(true)应该检测服务器何时关闭管道。

您应该考虑使用异步命名管道。