Работа с именованными каналами на Windows

Тема в разделе "WASM.WIN32", создана пользователем drem1lin, 21 июн 2017.

  1. drem1lin

    drem1lin Member

    Публикаций:
    0
    Регистрация:
    17 мар 2009
    Сообщения:
    300
    Всем привет, столкнулся с проблемой и сам себя запутал. В общем писал две программы для Android native на с++ и использовал pipe для передачи данных между ними. Соответственно со временем проект разросся и сейчас мне надо было все это дело отладить и я понял, что не могу подружиться с консольным gdb. Так как там платформозависимого кода нет, то решил заменить linux-pipe на winapi-pipe, и отладить все остальное. Соответственно я все перенес, но тут столкнулся с несколькими моментами:
    1. В линуксе я использовал mkfifo для создания pipe и она возвращает в errno EXIST если уже существует. В Windows я решил использовать CreateNamedPipe и так уж получается, что pipe создать могу, но если уже существует возвращается ACCESS_DENIED при повторном создании.
    2. Я изначально создавал два pipe, и открывал их крест на крест, то есть клиент открывал сначала тот который на запись, а сервер тот который на чтение и наоборот. На Windows я на сервере сделал ConnectNamedPipe и он блокируется до подключения клиента, а на клиенте СreateFile. Клиент нормально открывает pipe, но сервер все так же висит в ConnectNamedPipe. Вот тут мне не понятно почему..
    основной вопрос именно такой, как мне сделать в Windows поведение pipe такое же как в linux? что бы не менять логику работы?

    Код (Text):
    1.  
    2. #ifndef __PipeBaseClass_H__
    3. #define __PipeBaseClass_H__
    4.  
    5. #include <thread>
    6. #include <functional>
    7. #include <stdio.h>
    8.  
    9. #include <atomic>
    10.  
    11. #ifndef WIN32
    12. #include <unistd.h>
    13. #include <unistd.h>
    14. #include <sys/stat.h>
    15. #include <fcntl.h>
    16. #include <errno.h>
    17. #else
    18. #include <Windows.h>
    19. #endif
    20.  
    21. #define MAX_BUF 4096
    22.  
    23. class PipeBaseClass
    24. {
    25. public:
    26.     PipeBaseClass(const char* _pipeName, std::function<void(unsigned char*, unsigned int)> ReadCallBack)
    27.     {
    28.         memset(pipeForWriting, 0, 256*sizeof(char));
    29.         memset(pipeForReading, 0, 256*sizeof(char));
    30.         strcpy(pipeForWriting, _pipeName);
    31.         strcpy(pipeForReading, _pipeName);
    32.         //onRead = _onRead;
    33.         onReadCallback = ReadCallBack;
    34.         pipeForReadingDescriptor =0;
    35.         pipeForWritingDescriptor = 0;
    36.         ReadingThread = nullptr;
    37.         _isReadingThreadWorking = false;
    38.     };
    39.  
    40.     virtual int Connect() = 0;
    41.  
    42.     int Create()
    43.     {
    44. #ifndef WIN32
    45.         /* create the FIFO (named pipe) */
    46.         int ret = mkfifo(pipeForWriting, S_IFIFO|S_IRWXU|S_IRWXG|S_IRWXO);
    47.         if(ret!= 0 && errno!=EEXIST)
    48.         {
    49.             printf("create named pipe error = %d\n", errno); /* произошла ошибка */
    50.             return errno;
    51.         }
    52.         ret = mkfifo(pipeForReading, S_IFIFO|S_IRWXU|S_IRWXG|S_IRWXO);
    53.         if(ret!= 0 && errno!=EEXIST)
    54.         {
    55.             printf("create named pipe error = %d\n", errno); /* произошла ошибка */
    56.             return errno;
    57.         }
    58.         return 0;
    59. #else
    60.         hPipeRead = CreateNamedPipeA(pipeForReading, PIPE_ACCESS_INBOUND, PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT, PIPE_UNLIMITED_INSTANCES, 512, 512, 0, NULL);
    61.         if (hPipeRead == INVALID_HANDLE_VALUE)
    62.         {
    63.             DWORD d = GetLastError();
    64.             return 0xFFFFFFF;
    65.         }
    66.         hPipeWrite = CreateNamedPipeA(pipeForWriting, PIPE_ACCESS_OUTBOUND, PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT, PIPE_UNLIMITED_INSTANCES, 512, 512, 0, NULL);
    67.         if (hPipeWrite == INVALID_HANDLE_VALUE)
    68.         {
    69.             DWORD d = GetLastError();
    70.             return 0xFFFFFFF;
    71.         }
    72.         return 0;
    73. #endif // !WIN32
    74.     };
    75.    
    76.    
    77.     int Disconnect()
    78.     {
    79. #ifndef WIN32
    80.         close(pipeForReadingDescriptor);
    81.         close(pipeForWritingDescriptor);
    82. #else
    83.         if (hPipeWrite != INVALID_HANDLE_VALUE && hPipeWrite != 0)
    84.             DisconnectNamedPipe(hPipeWrite);
    85.         if (hPipeRead != INVALID_HANDLE_VALUE && hPipeRead != 0)
    86.             DisconnectNamedPipe(hPipeRead);
    87. #endif
    88.         Wait();
    89.         return 0;
    90.     };
    91.    
    92.     int Delete()
    93.     {
    94. #ifndef WIN32
    95.         unlink(pipeForReading);
    96.         unlink(pipeForWriting);
    97. #else
    98.         CloseHandle(hPipeWrite);
    99.         CloseHandle(hPipeRead);
    100. #endif
    101.         return 0;
    102.     };
    103.  
    104.     int Wait()
    105.     {
    106.         if(ReadingThread!=nullptr)
    107.         {  
    108.             printf("Wait\n");
    109.             ReadingThread->join();
    110.             ReadingThread = nullptr;
    111.         }
    112.         return 0;
    113.     };
    114.    
    115.     int Write(unsigned char * buffer, unsigned int bufferLen)
    116.     {
    117. #ifndef WIN32
    118.         return write(pipeForWritingDescriptor, buffer, bufferLen);
    119. #else
    120.         DWORD bytes = 0;
    121.         return WriteFile(hPipeWrite, buffer, bufferLen, &bytes, NULL);
    122. #endif
    123.     };
    124.  
    125.     virtual ~PipeBaseClass()
    126.     {  
    127.         pipeForWritingDescriptor = 0;
    128.         pipeForReadingDescriptor = 0;
    129. #ifndef WIN32
    130.         close(pipeForWritingDescriptor);
    131.         unlink(pipeForWriting);
    132.         close(pipeForReadingDescriptor);
    133.         unlink(pipeForReading);
    134. #endif
    135.     };
    136.  
    137.     int ReadingThreadFunc()
    138.     {
    139.         _isReadingThreadWorking = true;
    140.         unsigned char buf[MAX_BUF];
    141.         printf("ReadingThreadFunc start\n");
    142. #ifndef WIN32
    143.         ssize_t bytesReaded = 0;
    144.         do
    145.         {
    146.             if (pipeForReadingDescriptor==0)
    147.                 break;
    148.             bytesReaded = read(pipeForReadingDescriptor, buf, MAX_BUF);
    149.             if(onReadCallback!=NULL && bytesReaded )
    150.             {
    151.                 onReadCallback(buf, bytesReaded/*, this*/);
    152.                 //printf("data added\n");
    153.             }
    154.             memset(buf,0,MAX_BUF);
    155.         }while (bytesReaded>0);
    156.         printf("ReadingThreadFunc end %d\n", errno);
    157.         _isReadingThreadWorking = false;
    158.         return 0;
    159. #else
    160.         DWORD bytesReaded = 0;
    161.         do
    162.         {
    163.             if (hPipeRead == 0 || hPipeRead == INVALID_HANDLE_VALUE)
    164.                 break;
    165.             bytesReaded = ReadFile(hPipeRead, buf, MAX_BUF,&bytesReaded,NULL);
    166.             if (onReadCallback != NULL && bytesReaded)
    167.             {
    168.                 onReadCallback(buf, bytesReaded/*, this*/);
    169.                 //printf("data added\n");
    170.             }
    171.             memset(buf, 0, MAX_BUF);
    172.         } while (bytesReaded > 0);
    173.         printf("ReadingThreadFunc end %d\n", errno);
    174.         _isReadingThreadWorking = false;
    175.         return 0;
    176. #endif
    177.     };
    178.  
    179.     bool isReadingThreadWorking()
    180.     {
    181.         return _isReadingThreadWorking;
    182.     }
    183. protected:
    184.     char pipeForWriting[256];
    185.     char pipeForReading[256];
    186.     int pipeForWritingDescriptor;
    187.     int pipeForReadingDescriptor;
    188. #ifdef WIN32
    189.     HANDLE hPipeRead;
    190.     HANDLE hPipeWrite;
    191. #endif
    192.  
    193.  
    194.     std::function<void(unsigned char*, unsigned int)> onReadCallback;
    195.  
    196.     std::thread* ReadingThread;
    197.     std::atomic<bool> _isReadingThreadWorking;
    198. private:
    199.  
    200. };
    201.  
    202. #endif
    203.  
    Код (Text):
    1.  
    2. #ifndef __PipeServerClass_H__
    3. #define __PipeServerClass_H__
    4.  
    5. #include "PipeBaseClass.h"
    6.  
    7. class PipeServerClass: public PipeBaseClass
    8. {
    9. public:
    10.     PipeServerClass(const char* _pipeName):PipeServerClass(_pipeName, nullptr)
    11.     {
    12.  
    13.     };
    14.     PipeServerClass(const char* _pipeName, std::function<void(unsigned char*, unsigned int)> ReadCallBack):PipeBaseClass(_pipeName, ReadCallBack)
    15.     {
    16.         strncat(pipeForWriting, "_read", 5);
    17.         strncat(pipeForReading, "_write", 6);
    18.     };
    19.  
    20.     int Connect()
    21.     {
    22. #ifndef WIN32
    23.         if(pipeForReadingDescriptor!=0 && pipeForWritingDescriptor!=0)
    24.         {
    25.             printf("pipes already opened\n"); /* произошла ошибка */
    26.             return 0;
    27.         }
    28.         pipeForReadingDescriptor = open(pipeForReading, O_RDONLY);
    29.         if (pipeForReadingDescriptor == -1) {
    30.             printf("server pipeForReading open error = %d\n", errno); /* произошла ошибка */
    31.             return errno;
    32.         }
    33.  
    34.         pipeForWritingDescriptor = open(pipeForWriting, O_WRONLY);
    35.         if (pipeForWritingDescriptor == -1) {
    36.                 printf("server pipeForWriting open error = %d\n", errno); /* произошла ошибка */
    37.                 return errno;
    38.         }
    39. #else
    40.         if (FALSE == ConnectNamedPipe(hPipeRead, NULL))
    41.             return 1;
    42.  
    43.         if (FALSE == ConnectNamedPipe(hPipeWrite, NULL))
    44.             return 2;
    45. #endif
    46.  
    47.         ReadingThread = new std::thread(&PipeBaseClass::ReadingThreadFunc, this);
    48.         return 0;
    49.     };
    50.  
    51.     ~PipeServerClass()
    52.     {
    53.  
    54.     };
    55. private:
    56. };
    57.  
    58. #endif
    59.  
    Код (Text):
    1.  
    2. #ifndef __PipeClientClass_H__
    3. #define __PipeClientClass_H__
    4.  
    5. #include "PipeBaseClass.h"
    6.  
    7. class PipeClientClass:public PipeBaseClass
    8. {
    9. public:
    10.     PipeClientClass(const char* _pipeName):PipeClientClass(_pipeName, nullptr)
    11.     {
    12.  
    13.     };
    14.     PipeClientClass(const char* _pipeName, std::function<void(unsigned char*, unsigned int)> ReadCallBack):PipeBaseClass(_pipeName, ReadCallBack)
    15.     {
    16.         strncat(pipeForWriting, "_write", 6);
    17.         strncat(pipeForReading, "_read", 5);
    18.     };
    19.  
    20.     int Connect()
    21.     {
    22. #ifndef WIN32
    23.         if(pipeForReadingDescriptor!=0 && pipeForWritingDescriptor!=0)
    24.         {
    25.             printf("pipes already opened\n"); /* произошла ошибка */
    26.             return 0;
    27.         }
    28.         pipeForWritingDescriptor = open(pipeForWriting, O_WRONLY);
    29.         if (pipeForWritingDescriptor == -1) {
    30.             printf("client pipeForWriting open error = %d\n", errno); /* произошла ошибка */
    31.             return errno;
    32.         }
    33.         pipeForReadingDescriptor = open(pipeForReading, O_RDONLY);
    34.         if (pipeForReadingDescriptor == -1) {
    35.             printf("client pipeForReading open error = %d\n", errno); /* произошла ошибка */
    36.             return errno;
    37.         }
    38. #else
    39.         if (hPipeRead != 0 && hPipeRead != INVALID_HANDLE_VALUE)
    40.             CloseHandle(hPipeRead);
    41.         if (hPipeWrite != 0 && hPipeWrite != INVALID_HANDLE_VALUE)
    42.             CloseHandle(hPipeWrite);
    43.         hPipeRead = CreateFileA(pipeForReading, GENERIC_READ, FILE_SHARE_WRITE | FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
    44.         if (hPipeRead == INVALID_HANDLE_VALUE)
    45.             return GetLastError();
    46.         hPipeWrite = CreateFileA(pipeForWriting, GENERIC_READ, FILE_SHARE_WRITE | FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
    47.         if (hPipeRead == INVALID_HANDLE_VALUE)
    48.             return GetLastError();
    49. #endif
    50.  
    51.         ReadingThread = new std::thread(&PipeBaseClass::ReadingThreadFunc, this);
    52.         return 0;
    53.     };
    54.  
    55.     ~PipeClientClass()
    56.     {
    57.  
    58.     };
    59. private:
    60. };
    61.  
    62. #endif
    63.  
    64.  
     
  2. ol.

    ol. Active Member

    Публикаций:
    0
    Регистрация:
    21 фев 2017
    Сообщения:
    118
    Вот такой порт pipe() у меня работает на вин:
    Код (Text):
    1.  
    2. #ifdef _WIN32
    3. int pipe(int* pipes)
    4. {
    5.    static int id = 0;
    6.    char name[64];
    7.    snprintf(name, sizeof(name), "\\\\.\\pipe\\DEAD%d", ++id);
    8.  
    9.    HANDLE pipe1 = CreateNamedPipe(name,
    10.        PIPE_ACCESS_DUPLEX|WRITE_DAC,
    11.        PIPE_TYPE_BYTE|PIPE_READMODE_BYTE|PIPE_NOWAIT,
    12.        2, 1024, 1024, 2000, NULL);
    13.  
    14.    HANDLE pipe2 = CreateFile(name,
    15.        GENERIC_WRITE, 0,
    16.        NULL,
    17.        OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL,
    18.        NULL);
    19.  
    20.    pipes[0] = pipe1;
    21.    pipes[1] = pipe2;
    22.  
    23.    return 0;
    24. }
    25. #endif
    26.