1 Востаннє редагувалося Betterthanyou (14.03.2019 17:58:44)

Тема: IPC між програмами написаними на С++ і C# за допомогою Named Pipe

Має бути так: Програма написана на C# (сервер) запускає програму написану на С++ (клієнт) і ця програма передає повідомлення (у вигляді байтів) у програму сервер

Код клієнта

#include <stdio.h>
#include <windows.h>

int main(int argc, char *argv[])
{
    HANDLE hPipe;

    //Pipe Init Data
    const unsigned short bufSize = 1000;
    char buf[bufSize];

    LPTSTR lpszPipename = TEXT("\\\\.\\pipe\\myNamedPipe");

    DWORD cbWritten;
    DWORD dwBytesToWrite = (DWORD)strlen(buf);

    hPipe = CreateFile(lpszPipename, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);

    if (hPipe == NULL || hPipe == INVALID_HANDLE_VALUE)
    {
        printf("Could not open the pipe  - (error %d)\n", GetLastError());
    }
    else
    {
        do
        {
            printf("Enter your message: ");
            scanf("%s", buf);
            WriteFile(hPipe, buf, dwBytesToWrite, &cbWritten, NULL);
            memset(buf, 0, bufSize);
        } while (TRUE);

        CloseHandle(hPipe);
    }
    printf("App is stopped");
    getchar();
}

Код серверу (складається з двох файлів класу NamedPipeServer і функції main)

using System;
using Microsoft.Win32.SafeHandles;
using System.Text;
using System.Runtime.InteropServices;
using System.Threading;
using System.IO;

namespace CSNamedPipe
{
    public class NamedPipeServer
    {
        [DllImport("kernel32.dll", SetLastError = true)]
        public static extern SafeFileHandle CreateNamedPipe(
           String pipeName,
           uint dwOpenMode,
           uint dwPipeMode,
           uint nMaxInstances,
           uint nOutBufferSize,
           uint nInBufferSize,
           uint nDefaultTimeOut,
           IntPtr lpSecurityAttributes);

        [DllImport("kernel32.dll", SetLastError = true)]
        public static extern int ConnectNamedPipe(
           SafeFileHandle hNamedPipe,
           IntPtr lpOverlapped);

        [DllImport("kernel32.dll", SetLastError = true)]
        public static extern int DisconnectNamedPipe(
           SafeFileHandle hNamedPipe);

        public const uint DUPLEX = (0x00000003);
        public const uint FILE_FLAG_OVERLAPPED = (0x40000000);

        public class Client
        {
            public SafeFileHandle handle;
            public FileStream stream;
        }

        public const int BUFFER_SIZE = 1000;
        public Client clientse = null;

        public string pipeName;
        Thread listenThread;
        SafeFileHandle clientHandle;

        public NamedPipeServer(string PName)
        {
            pipeName = PName;
        }       
        public void Start()
        {
            listenThread = new Thread(new ThreadStart(ListenForClients));
            listenThread.Start();
        }
        private void ListenForClients()
        {
            while (true)
            {
                clientHandle = CreateNamedPipe(
                    pipeName,
                    DUPLEX | FILE_FLAG_OVERLAPPED,
                    0,
                    255,
                    BUFFER_SIZE,
                    BUFFER_SIZE,
                    0,
                    IntPtr.Zero
                    );

                //could not create named pipe
                if (clientHandle.IsInvalid)
                {
                    return;
                }

                int success = ConnectNamedPipe(clientHandle, IntPtr.Zero);

                //could not connect client
                if (success == 0)
                {
                    return;
                }

                clientse = new Client();
                clientse.handle = clientHandle;
                clientse.stream = new FileStream(clientse.handle, FileAccess.Read, BUFFER_SIZE);

                Thread readThread = new Thread(new ThreadStart(Read));
                readThread.Start();                

                Thread.Sleep(1000);
            }
        }
        private void Read()
        {
            byte[] buffer = null;
            ASCIIEncoding encoder = new ASCIIEncoding();
            while (true)
            {
                int bytesRead = 0;

                buffer = new byte[BUFFER_SIZE];
                bytesRead = clientse.stream.Read(buffer, 0, BUFFER_SIZE);

                //client has disconnected
                if (bytesRead == 0)
                {
                    break;
                }

                Console.WriteLine("read >>> " + Encoding.ASCII.GetString(buffer));
                buffer.Initialize();

                Thread.Sleep(1000);
            }
            //clean up resources            
            clientse.stream.Close();
            clientse.handle.Close();            
        }
        public void StopServer()
        {
            //clean up resources
            DisconnectNamedPipe(clientHandle);
            listenThread.Abort();
        }

    }
}
using System;
namespace CSNamedPipe
{
    class Program
    {
        static void Main(string[] args)
        {
            NamedPipeServer PServer1 = new NamedPipeServer(@"\\.\pipe\myNamedPipe");
            PServer1.Start();
            Console.ReadKey();
            PServer1.StopServer();
        }
    }
}

Проблема в тому що повідомлення проходять не повні або взагалі не приходять

Приклад вводу - 1234567890qwertyuio
Сервер виводить - 123


Я ще пробував імпортувати функцію CreateFile i ReadFile в сервер але не вийшло підібрати параметри... тому користуюся інструментами C# FileStream

В чому може бути проблема ? Чому повідомлення не передаються повністю ?

2

Re: IPC між програмами написаними на С++ і C# за допомогою Named Pipe

Сервер чомусь перестворює пайп у циклі.
Ви читали документацію по прапорцю FILE_FLAG_OVERLAPPED? Точно певні, що вам саме це треба?

Подякували: Betterthanyou1

3

Re: IPC між програмами написаними на С++ і C# за допомогою Named Pipe

Я видалив цикл та замінив прапор на PIPE_ACCESS_INBOUND "The flow of data in the pipe goes from client to server only"

code
using System;
using Microsoft.Win32.SafeHandles;
using System.Text;
using System.Runtime.InteropServices;
using System.Threading;
using System.IO;

namespace CSNamedPipe
{
    public class NamedPipeServer
    {
        [DllImport("kernel32.dll", SetLastError = true)]
        public static extern SafeFileHandle CreateNamedPipe(
           String pipeName,
           uint dwOpenMode,
           uint dwPipeMode,
           uint nMaxInstances,
           uint nOutBufferSize,
           uint nInBufferSize,
           uint nDefaultTimeOut,
           IntPtr lpSecurityAttributes);

        [DllImport("kernel32.dll", SetLastError = true)]
        public static extern int ConnectNamedPipe(
           SafeFileHandle hNamedPipe,
           IntPtr lpOverlapped);

        [DllImport("kernel32.dll", SetLastError = true)]
        public static extern int DisconnectNamedPipe(
           SafeFileHandle hNamedPipe);

        public const uint PIPE_ACCESS_INBOUND = (0x00000001);

        public class Client
        {
            public SafeFileHandle handle;
            public FileStream stream;
        }

        public const int BUFFER_SIZE = 1000;
        public Client clientse = null;

        public string pipeName;
        Thread listenThread;
        SafeFileHandle clientHandle;

        public NamedPipeServer(string PName)
        {
            pipeName = PName;
        }       
        public void Start()
        {
            Console.WriteLine("Start Start");
            listenThread = new Thread(new ThreadStart(ListenForClients));
            listenThread.Start();
            Console.WriteLine("Start End");
        }
        private void ListenForClients()
        {
            Console.WriteLine("Start ListenForClients");
            clientHandle = CreateNamedPipe(
                pipeName,
                PIPE_ACCESS_INBOUND,
                0,
                255,
                BUFFER_SIZE,
                BUFFER_SIZE,
                0,
                IntPtr.Zero
                );

            //could not create named pipe
            if (clientHandle.IsInvalid)
            {
                Console.WriteLine("Error!");
                return;
            }

            int success = ConnectNamedPipe(clientHandle, IntPtr.Zero);

            //could not connect client
            if (success == 0)
            {
                Console.WriteLine("Error!");
                return;
            }

            clientse = new Client();
            clientse.handle = clientHandle;
            clientse.stream = new FileStream(clientse.handle, FileAccess.Read, BUFFER_SIZE);

            Thread readThread = new Thread(new ThreadStart(Read));
            readThread.Start();
            Console.WriteLine("ListenForClients End");
        }
        private void Read()
        {
            Console.WriteLine("Start Read");
            byte[] buffer = null;
            ASCIIEncoding encoder = new ASCIIEncoding();
            while (true)
            {
                int bytesRead = 0;

                buffer = new byte[BUFFER_SIZE];
                bytesRead = clientse.stream.Read(buffer, 0, BUFFER_SIZE);

                //client has disconnected
                if (bytesRead == 0)
                {
                    break;
                }

                Console.WriteLine("read >>> " + Encoding.ASCII.GetString(buffer));
                buffer.Initialize();

                Thread.Sleep(1000);
            }
            //clean up resources            
            clientse.stream.Close();
            clientse.handle.Close();
            Console.WriteLine("Start End");
        }
        public void StopServer()
        {
            Console.WriteLine("Start StopServer");
            //clean up resources
            DisconnectNamedPipe(clientHandle);
            listenThread.Abort();
            Console.WriteLine("End StopServer");
        }

    }
}

Але проблема не зникла

Ось скріншот
https://i.ibb.co/d4T1VhY/Untitled.png

4 Востаннє редагувалося Betterthanyou (14.03.2019 21:28:59)

Re: IPC між програмами написаними на С++ і C# за допомогою Named Pipe

Мені вдалося передати дані через сокет, але питання ще актуальне: Як передати дані між програмами написаними на С++ і С# ?

5 Востаннє редагувалося koala (15.03.2019 07:39:53)

Re: IPC між програмами написаними на С++ і C# за допомогою Named Pipe

До речі, а нащо ви в C# руками до DLLьок чіпляєтеся? Є ж System.IO.Pipes.

Подякували: leofun01, Betterthanyou, varkon3

6

Re: IPC між програмами написаними на С++ і C# за допомогою Named Pipe

Так, дякую. Про System.IO.Pipes я не знав

Знайшов такий приклад
https://www.codeproject.com/Articles/11 … -Named-Pip

Тепер передача даних працює як потрібно.