Всем привет, столкнулся с проблемой и сам себя запутал. В общем писал две программы для Android native на с++ и использовал pipe для передачи данных между ними. Соответственно со временем проект разросся и сейчас мне надо было все это дело отладить и я понял, что не могу подружиться с консольным gdb. Так как там платформозависимого кода нет, то решил заменить linux-pipe на winapi-pipe, и отладить все остальное. Соответственно я все перенес, но тут столкнулся с несколькими моментами: В линуксе я использовал mkfifo для создания pipe и она возвращает в errno EXIST если уже существует. В Windows я решил использовать CreateNamedPipe и так уж получается, что pipe создать могу, но если уже существует возвращается ACCESS_DENIED при повторном создании. Я изначально создавал два pipe, и открывал их крест на крест, то есть клиент открывал сначала тот который на запись, а сервер тот который на чтение и наоборот. На Windows я на сервере сделал ConnectNamedPipe и он блокируется до подключения клиента, а на клиенте СreateFile. Клиент нормально открывает pipe, но сервер все так же висит в ConnectNamedPipe. Вот тут мне не понятно почему.. основной вопрос именно такой, как мне сделать в Windows поведение pipe такое же как в linux? что бы не менять логику работы? Спойлер: Вот текущая реализация Спойлер: Базовый класс Код (Text): #ifndef __PipeBaseClass_H__ #define __PipeBaseClass_H__ #include <thread> #include <functional> #include <stdio.h> #include <atomic> #ifndef WIN32 #include <unistd.h> #include <unistd.h> #include <sys/stat.h> #include <fcntl.h> #include <errno.h> #else #include <Windows.h> #endif #define MAX_BUF 4096 class PipeBaseClass { public: PipeBaseClass(const char* _pipeName, std::function<void(unsigned char*, unsigned int)> ReadCallBack) { memset(pipeForWriting, 0, 256*sizeof(char)); memset(pipeForReading, 0, 256*sizeof(char)); strcpy(pipeForWriting, _pipeName); strcpy(pipeForReading, _pipeName); //onRead = _onRead; onReadCallback = ReadCallBack; pipeForReadingDescriptor =0; pipeForWritingDescriptor = 0; ReadingThread = nullptr; _isReadingThreadWorking = false; }; virtual int Connect() = 0; int Create() { #ifndef WIN32 /* create the FIFO (named pipe) */ int ret = mkfifo(pipeForWriting, S_IFIFO|S_IRWXU|S_IRWXG|S_IRWXO); if(ret!= 0 && errno!=EEXIST) { printf("create named pipe error = %d\n", errno); /* произошла ошибка */ return errno; } ret = mkfifo(pipeForReading, S_IFIFO|S_IRWXU|S_IRWXG|S_IRWXO); if(ret!= 0 && errno!=EEXIST) { printf("create named pipe error = %d\n", errno); /* произошла ошибка */ return errno; } return 0; #else hPipeRead = CreateNamedPipeA(pipeForReading, PIPE_ACCESS_INBOUND, PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT, PIPE_UNLIMITED_INSTANCES, 512, 512, 0, NULL); if (hPipeRead == INVALID_HANDLE_VALUE) { DWORD d = GetLastError(); return 0xFFFFFFF; } hPipeWrite = CreateNamedPipeA(pipeForWriting, PIPE_ACCESS_OUTBOUND, PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT, PIPE_UNLIMITED_INSTANCES, 512, 512, 0, NULL); if (hPipeWrite == INVALID_HANDLE_VALUE) { DWORD d = GetLastError(); return 0xFFFFFFF; } return 0; #endif // !WIN32 }; int Disconnect() { #ifndef WIN32 close(pipeForReadingDescriptor); close(pipeForWritingDescriptor); #else if (hPipeWrite != INVALID_HANDLE_VALUE && hPipeWrite != 0) DisconnectNamedPipe(hPipeWrite); if (hPipeRead != INVALID_HANDLE_VALUE && hPipeRead != 0) DisconnectNamedPipe(hPipeRead); #endif Wait(); return 0; }; int Delete() { #ifndef WIN32 unlink(pipeForReading); unlink(pipeForWriting); #else CloseHandle(hPipeWrite); CloseHandle(hPipeRead); #endif return 0; }; int Wait() { if(ReadingThread!=nullptr) { printf("Wait\n"); ReadingThread->join(); ReadingThread = nullptr; } return 0; }; int Write(unsigned char * buffer, unsigned int bufferLen) { #ifndef WIN32 return write(pipeForWritingDescriptor, buffer, bufferLen); #else DWORD bytes = 0; return WriteFile(hPipeWrite, buffer, bufferLen, &bytes, NULL); #endif }; virtual ~PipeBaseClass() { pipeForWritingDescriptor = 0; pipeForReadingDescriptor = 0; #ifndef WIN32 close(pipeForWritingDescriptor); unlink(pipeForWriting); close(pipeForReadingDescriptor); unlink(pipeForReading); #endif }; int ReadingThreadFunc() { _isReadingThreadWorking = true; unsigned char buf[MAX_BUF]; printf("ReadingThreadFunc start\n"); #ifndef WIN32 ssize_t bytesReaded = 0; do { if (pipeForReadingDescriptor==0) break; bytesReaded = read(pipeForReadingDescriptor, buf, MAX_BUF); if(onReadCallback!=NULL && bytesReaded ) { onReadCallback(buf, bytesReaded/*, this*/); //printf("data added\n"); } memset(buf,0,MAX_BUF); }while (bytesReaded>0); printf("ReadingThreadFunc end %d\n", errno); _isReadingThreadWorking = false; return 0; #else DWORD bytesReaded = 0; do { if (hPipeRead == 0 || hPipeRead == INVALID_HANDLE_VALUE) break; bytesReaded = ReadFile(hPipeRead, buf, MAX_BUF,&bytesReaded,NULL); if (onReadCallback != NULL && bytesReaded) { onReadCallback(buf, bytesReaded/*, this*/); //printf("data added\n"); } memset(buf, 0, MAX_BUF); } while (bytesReaded > 0); printf("ReadingThreadFunc end %d\n", errno); _isReadingThreadWorking = false; return 0; #endif }; bool isReadingThreadWorking() { return _isReadingThreadWorking; } protected: char pipeForWriting[256]; char pipeForReading[256]; int pipeForWritingDescriptor; int pipeForReadingDescriptor; #ifdef WIN32 HANDLE hPipeRead; HANDLE hPipeWrite; #endif std::function<void(unsigned char*, unsigned int)> onReadCallback; std::thread* ReadingThread; std::atomic<bool> _isReadingThreadWorking; private: }; #endif Спойлер: Сервер Код (Text): #ifndef __PipeServerClass_H__ #define __PipeServerClass_H__ #include "PipeBaseClass.h" class PipeServerClass: public PipeBaseClass { public: PipeServerClass(const char* _pipeName):PipeServerClass(_pipeName, nullptr) { }; PipeServerClass(const char* _pipeName, std::function<void(unsigned char*, unsigned int)> ReadCallBack):PipeBaseClass(_pipeName, ReadCallBack) { strncat(pipeForWriting, "_read", 5); strncat(pipeForReading, "_write", 6); }; int Connect() { #ifndef WIN32 if(pipeForReadingDescriptor!=0 && pipeForWritingDescriptor!=0) { printf("pipes already opened\n"); /* произошла ошибка */ return 0; } pipeForReadingDescriptor = open(pipeForReading, O_RDONLY); if (pipeForReadingDescriptor == -1) { printf("server pipeForReading open error = %d\n", errno); /* произошла ошибка */ return errno; } pipeForWritingDescriptor = open(pipeForWriting, O_WRONLY); if (pipeForWritingDescriptor == -1) { printf("server pipeForWriting open error = %d\n", errno); /* произошла ошибка */ return errno; } #else if (FALSE == ConnectNamedPipe(hPipeRead, NULL)) return 1; if (FALSE == ConnectNamedPipe(hPipeWrite, NULL)) return 2; #endif ReadingThread = new std::thread(&PipeBaseClass::ReadingThreadFunc, this); return 0; }; ~PipeServerClass() { }; private: }; #endif Спойлер: Клиент Код (Text): #ifndef __PipeClientClass_H__ #define __PipeClientClass_H__ #include "PipeBaseClass.h" class PipeClientClass:public PipeBaseClass { public: PipeClientClass(const char* _pipeName):PipeClientClass(_pipeName, nullptr) { }; PipeClientClass(const char* _pipeName, std::function<void(unsigned char*, unsigned int)> ReadCallBack):PipeBaseClass(_pipeName, ReadCallBack) { strncat(pipeForWriting, "_write", 6); strncat(pipeForReading, "_read", 5); }; int Connect() { #ifndef WIN32 if(pipeForReadingDescriptor!=0 && pipeForWritingDescriptor!=0) { printf("pipes already opened\n"); /* произошла ошибка */ return 0; } pipeForWritingDescriptor = open(pipeForWriting, O_WRONLY); if (pipeForWritingDescriptor == -1) { printf("client pipeForWriting open error = %d\n", errno); /* произошла ошибка */ return errno; } pipeForReadingDescriptor = open(pipeForReading, O_RDONLY); if (pipeForReadingDescriptor == -1) { printf("client pipeForReading open error = %d\n", errno); /* произошла ошибка */ return errno; } #else if (hPipeRead != 0 && hPipeRead != INVALID_HANDLE_VALUE) CloseHandle(hPipeRead); if (hPipeWrite != 0 && hPipeWrite != INVALID_HANDLE_VALUE) CloseHandle(hPipeWrite); hPipeRead = CreateFileA(pipeForReading, GENERIC_READ, FILE_SHARE_WRITE | FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (hPipeRead == INVALID_HANDLE_VALUE) return GetLastError(); hPipeWrite = CreateFileA(pipeForWriting, GENERIC_READ, FILE_SHARE_WRITE | FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (hPipeRead == INVALID_HANDLE_VALUE) return GetLastError(); #endif ReadingThread = new std::thread(&PipeBaseClass::ReadingThreadFunc, this); return 0; }; ~PipeClientClass() { }; private: }; #endif
Вот такой порт pipe() у меня работает на вин: Код (Text): #ifdef _WIN32 int pipe(int* pipes) { static int id = 0; char name[64]; snprintf(name, sizeof(name), "\\\\.\\pipe\\DEAD%d", ++id); HANDLE pipe1 = CreateNamedPipe(name, PIPE_ACCESS_DUPLEX|WRITE_DAC, PIPE_TYPE_BYTE|PIPE_READMODE_BYTE|PIPE_NOWAIT, 2, 1024, 1024, 2000, NULL); HANDLE pipe2 = CreateFile(name, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); pipes[0] = pipe1; pipes[1] = pipe2; return 0; } #endif