C# 命名管道双向通信

本文关键字:双向通信 管道 | 更新日期: 2023-09-27 18:35:32

我有两个用 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);
    }

C# 命名管道双向通信

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

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

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

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