Название: pipe каналы
Отправлено: Firefox от Июля 19, 2011, 23:42
добрый день. вот начала разбираться с pipe каналами между двумя программами. я делаю это на одном компе не по сети. написала 2 класса один подключается к программе 1 она будет сервером, второй к программе 2 она будет клиентом. написала отдельными классами, так как у каждой программы есть свое предназначение и создание каналов служит лишь для обмена данными. столкнулась с такой проблемой: если при создании канала пользоваться флагом PIPE_WAIT, то виснет вся программа(даже форму не развернуть), но данные по каналу передаются, если же флагом PIPE_NOWAIT, то никак не конектится клиент к серверу. вот программы //СЕРВЕР //.h #include <QtGui/QMainWindow> #include "ui_server_pipe.h" #include <QTimer> #include <QString> #include <QThread> class channel: public QThread { Q_OBJECT public: channel(); ~channel(); QTimer *tpipe; void run(); void createChannel(); void writeChannel(); private slots: void readChannel();
};
//.cpp #include "channel.h" #include <windows.h> #include <stdio.h> #include <conio.h> #include <QTimer>
QString str; // Флаг успешного создания канала BOOL fConnected;
// Идентификатор канала Pipe HANDLE hNamedPipe;
// Имя создаваемого канала Pipe LPCTSTR lpszPipeName =L"\\\\.\\pipe\\$MyPipe$";
// Буфер для передачи данных через канал char szBuf[512];
// Количество байт данных, принятых через канал DWORD cbRead; // Количество байт данных, переданных через канал DWORD cbWritten; bool flag=0,flag_exit=0;
channel::channel() {
} channel::~channel() { DisconnectNamedPipe(hNamedPipe); CloseHandle(hNamedPipe); } void channel::createChannel() {
metka: ; // Создаем канал Pipe, имеющий имя lpszPipeName hNamedPipe = CreateNamedPipe( lpszPipeName, PIPE_ACCESS_DUPLEX, PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_NOWAIT, PIPE_UNLIMITED_INSTANCES, 512, 512, 10000, NULL);
// Если возникла ошибка, выводим ее код и завершаем // работу приложения if(hNamedPipe == INVALID_HANDLE_VALUE) { str+="CreateNamedPipe: Error %ld\n"+GetLastError(); fprintf(stdout,"CreateNamedPipe: Error %ld\n", GetLastError()); getch(); goto metka; }
// Выводим сообщение о начале процесса создания канала fprintf(stdout,"Waiting for connect...\n"); tpipe->start(500); exec();
} void channel::readChannel() { bool flag_read=false; if(!fConnected) // Ожидаем соединения со стороны клиента fConnected = ConnectNamedPipe(hNamedPipe, NULL);
// При возникновении ошибки выводим ее код if(!fConnected) { flag_read=1; //switch(GetLastError()) //{ //case ERROR_NO_DATA: // str+="ConnectNamedPipe: ERROR_NO_DATA"; // //uicl->textEdit->setText(str); // //fprintf(stdout,"ConnectNamedPipe: ERROR_NO_DATA"); // flag_read=1; //// getch(); //// CloseHandle(hNamedPipe); //// return; // break;
//case ERROR_PIPE_CONNECTED: // str+="ConnectNamedPipe: ERROR_PIPE_CONNECTED"; // // //uicl->textEdit->setText(str); // //fprintf(stdout,"ConnectNamedPipe: ERROR_PIPE_CONNECTED"); // flag_read=1; // //getch(); // //return; // break;
//case ERROR_PIPE_LISTENING: // //str+="ConnectNamedPipe: ERROR_PIPE_LISTENING"; // //ui.textEdit->setText(str); // //fprintf(stdout,"ConnectNamedPipe: ERROR_PIPE_LISTENING"); // flag_read=1; // //getch(); // //CloseHandle(hNamedPipe); // //return; // break;
//case ERROR_CALL_NOT_IMPLEMENTED: // str+="ConnectNamedPipe: ERROR_CALL_NOT_IMPLEMENTED"; // //uicl->textEdit->setText(str); //// fprintf(stdout,"ConnectNamedPipe: ERROR_CALL_NOT_IMPLEMENTED"); // flag_read=1; //// getch(); // //CloseHandle(hNamedPipe); // //return; // break;
//default: // str+="ConnectNamedPipe: Error %ld\n"+GetLastError(); // // ui.textEdit->setText(str); //// fprintf(stdout,"ConnectNamedPipe: Error %ld\n", GetLastError()); // flag_read=1; //// getch(); // //CloseHandle(hNamedPipe); //// return; // break; //} //CloseHandle(hNamedPipe); //getch(); //return; }
// Цикл получения команд через канал if(flag_read==false) { if(flag==0) {
flag=1; } // Выводим сообщение об успешном создании канала fprintf(stdout,"\nConnected. Waiting for command...\n"); QString last_command=""; // Получаем очередную команду через канал Pipe if(ReadFile(hNamedPipe, szBuf, sizeof(szBuf), &cbRead, NULL)) { for (int i=0;i<512 && szBuf[i]!='\0';i++) { last_command+=szBuf[i]; } fprintf(stdout,/*"Received:\n"*/szBuf);
if(last_command=="exit") { exit(); flag_exit=1; } else flag_exit=0; } else { fprintf(stdout,"ReadFile: Error %ld\n #330033", GetLastError()); getch(); } if(flag_exit==1) { szBuf[0]='c'; szBuf[1]='l'; szBuf[2]='o'; szBuf[3]='s'; szBuf[4]='e'; for (int i=5;i<512;i++) szBuf[i]='\0'; WriteFile(hNamedPipe, szBuf, strlen(szBuf) + 1,&cbWritten, NULL); } } } void channel::run() { tpipe= new QTimer(); connect(tpipe,SIGNAL(timeout()),SLOT(readChannel())); createChannel(); }
//КЛИЕНТ //.h #include <QString> #include <windows.h> #include <stdio.h> #include <conio.h> #include <QTimer> #include <QThread>
class chanel_pipe: public QThread { Q_OBJECT public: chanel_pipe(); ~chanel_pipe(); QTimer *Ttime; void run(); bool read_chanel(); void write_chanel(char string_ch[20]); protected: private slots: void slot_read(); }; // .cpp #include "chanel_pipe.h"
// Идентификатор канала Pipe HANDLE hNamedPipe;
// Количество байт, переданных через канал DWORD cbWritten;
// Количество байт, принятых через канал DWORD cbRead;
// Буфер для передачи данных char szBuf[256];
chanel_pipe::chanel_pipe() { // Создаем канал с процессом PIPES hNamedPipe = CreateFile( L"\\\\.\\pipe\\$MyPipe$", GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
// Если возникла ошибка, выводим ее код и // завершаем работу приложения if(hNamedPipe == INVALID_HANDLE_VALUE) { fprintf(stdout,"CreateFile: Error %ld\n", GetLastError()); getch(); }
} chanel_pipe::~chanel_pipe() {
} bool chanel_pipe::read_chanel() { if(!hNamedPipe) { // Создаем канал с процессом PIPES hNamedPipe = CreateFile( L"\\\\.\\pipe\\$MyPipe$", GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
// Если возникла ошибка, выводим ее код и // завершаем работу приложения if(hNamedPipe == INVALID_HANDLE_VALUE) { fprintf(stdout,"CreateFile: Error %ld\n", GetLastError()); getch(); } }
bool rez=ReadFile(hNamedPipe, szBuf, strlen(szBuf)+1, &cbRead, NULL); QString str; for(int i=0;i<512;i++)str=str+szBuf[i]; if(str=="exit") { return 0; } return 1; } void chanel_pipe::write_chanel(char string_ch[20]) { if(!hNamedPipe) { // Создаем канал с процессом PIPES hNamedPipe = CreateFile( L"\\\\.\\pipe\\$MyPipe$", GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
// Если возникла ошибка, выводим ее код и // завершаем работу приложения if(hNamedPipe == INVALID_HANDLE_VALUE) { fprintf(stdout,"CreateFile: Error %ld\n", GetLastError()); getch(); } else WriteFile(hNamedPipe, string_ch, strlen(string_ch) + 1, &cbWritten, NULL); } else WriteFile(hNamedPipe, string_ch, strlen(string_ch) + 1, &cbWritten, NULL); } void chanel_pipe::slot_read() { bool rr=false; if(hNamedPipe) rr=read_chanel(); } void chanel_pipe::run() { Ttime=new QTimer; connect(Ttime,SIGNAL(timeout()),this,SLOT(slot_read())); Ttime->start(500); exec(); }
получается что если флаг PIPE_WAIT то при чтении с канала до следующего чтения блокируется все. как это можно изменить не знаю. или как так сделать чтою клиент смог подключиться без использования ожтдания. вроде классы создала в отдельном потоке а всеравно основной тоже грузиться. я только начала каналы изучать буду рада помощи.
Название: Re: pipe каналы
Отправлено: LisandreL от Июля 20, 2011, 06:43
goto metka; http://xkcd.ru/292/ если при создании канала пользоваться флагом PIPE_WAIT Потоки запускаете, разумеется, через run(), а не через start? P.S. Да и вообще есть QLocalSocket + QLocalServer. Зачем изобретать велосипед на WinAPI? On Windows this is a named pipe and on Unix this is a local domain socket.
Название: Re: pipe каналы
Отправлено: Firefox от Июля 20, 2011, 09:34
запускаю конечно через start(). ну раз уж начала таким путем то хочется его все же разобрать. да и на работе стоит qt 4.3.3 и там как я посмотрела в хелпе нет этих классов.
Название: Re: pipe каналы
Отправлено: Firefox от Июля 20, 2011, 11:19
вот немного поразбиралась с асинхронным режимом передачи. получилось следующее, но всеравно не конектится: // СЕРВЕР //.h #include <QtGui/QMainWindow> #include "ui_server_pipe.h" #include <windows.h> #include <stdio.h> #include <conio.h> #include <QTimer> #include <QString> #include <QThread> class channel: public QThread { Q_OBJECT public: channel(); ~channel(); QTimer *tpipe; OVERLAPPED StrOverlapp; //Ui_server_pipeClass uicl; void run(); void createChannel(); void writeChannel(); private slots: void readChannel();
}; //.cpp #include "channel.h"
QString str; // Флаг успешного создания канала BOOL fConnected; // Идентификатор события HANDLE hEvent;
// Идентификатор канала Pipe HANDLE hNamedPipe;
// Имя создаваемого канала Pipe LPCTSTR lpszPipeName =L"\\\\.\\pipe\\$MyPipe$";
// Буфер для передачи данных через канал char szBuf[512];
// Количество байт данных, принятых через канал DWORD cbRead; // Количество байт данных, переданных через канал DWORD cbWritten; bool flag=0,flag_exit=0;
Ui_server_pipeClass uicl; channel::channel() { } channel::~channel() { DisconnectNamedPipe(hNamedPipe); CloseHandle(hNamedPipe); } void channel::createChannel() {
hEvent=CreateEvent(NULL,FALSE,FALSE, NULL); StrOverlapp.hEvent=hEvent; StrOverlapp.Offset=0; // TRANSFER HANDLE TEST >! StrOverlapp.OffsetHigh=0;
while(!hNamedPipe) { // Создаем канал Pipe, имеющий имя lpszPipeName hNamedPipe = CreateNamedPipe( lpszPipeName, // имя канала. PIPE_ACCESS_DUPLEX |FILE_FLAG_OVERLAPPED , /*асинхрон*/ PIPE_TYPE_MESSAGE, 10, // максимальное количество экземпляров канала. 512, // размер выходного буфера по умолчанию. 512, // рахмер входного буфера по умолчанию. INFINITE, // клиент ждет связь бесконечно долго. NULL // безопасность по умолчанию. );
// Если возникла ошибка, выводим ее код и завершаем // работу приложения if(hNamedPipe == INVALID_HANDLE_VALUE) { str+="CreateNamedPipe: Error %ld\n"+GetLastError(); fprintf(stdout,"CreateNamedPipe: Error %ld\n", GetLastError()); } } // Выводим сообщение о начале процесса создания канала str+="Waiting for connect...\n"; fprintf(stdout,"Waiting for connect...\n"); tpipe->start(50); exec(); } void channel::readChannel() { bool flag_read=false; if(!fConnected) // Ожидаем соединения со стороны клиента fConnected = ConnectNamedPipe(hNamedPipe, &StrOverlapp);
// При возникновении ошибки выводим ее код if(!fConnected) { flag_read=1; }
// Цикл получения команд через канал if(flag_read==false) { // Выводим сообщение об успешном создании канала fprintf(stdout,"\nConnected. Waiting for command...\n"); QString last_command=""; // Получаем очередную команду через канал Pipe if(ReadFile(hNamedPipe, szBuf, sizeof(szBuf), &cbRead, NULL)) { for (int i=0;i<512 && szBuf[i]!='\0';i++) { str+=szBuf[i]; last_command+=szBuf[i]; } fprintf(stdout,/*"Received:\n"*/szBuf);
if(last_command=="exit") { exit(); flag_exit=1; } else flag_exit=0; } else { fprintf(stdout,"ReadFile: Error %ld\n #330033", GetLastError()); getch(); } if(flag_exit==1) { szBuf[0]='c'; szBuf[1]='l'; szBuf[2]='o'; szBuf[3]='s'; szBuf[4]='e'; for (int i=5;i<512;i++) szBuf[i]='\0'; WriteFile(hNamedPipe, szBuf, strlen(szBuf) + 1,&cbWritten, NULL); } } } void channel::run() { tpipe= new QTimer(); connect(tpipe,SIGNAL(timeout()),SLOT(readChannel())); createChannel(); }
// запуск из главного потока: ch=new channel(); ch->start(QThread::HighPriority);
//КЛИЕНТ //.h #include <QString> #include <windows.h> #include <stdio.h> #include <conio.h> #include <QTimer> #include <QThread>
class chanel_pipe: public QThread { Q_OBJECT public: chanel_pipe(); ~chanel_pipe(); QTimer *Ttime; OVERLAPPED OVL; void run(); bool read_chanel(); void write_chanel(char string_ch[20]); protected: private slots: void slot_read(); }; //.cpp #include "chanel_pipe.h"
// Идентификатор канала Pipe HANDLE hNamedPipe; // Идентификатор события HANDLE hEndWrite; // Количество байт, переданных через канал DWORD cbWritten;
// Количество байт, принятых через канал DWORD cbRead;
// Буфер для передачи данных char szBuf[256];
chanel_pipe::chanel_pipe() {
} chanel_pipe::~chanel_pipe() {
} bool chanel_pipe::read_chanel() { if(!hNamedPipe) { // Создаем канал с процессом PIPES hNamedPipe = CreateFile( L"\\\\.\\pipe\\$MyPipe$", GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
// Если возникла ошибка, выводим ее код и // завершаем работу приложения if(hNamedPipe == INVALID_HANDLE_VALUE) { fprintf(stdout,"CreateFile: Error %ld\n", GetLastError()); getch(); } }
bool rez=ReadFile(hNamedPipe, szBuf, strlen(szBuf)+1, &cbRead, NULL); QString str; for(int i=0;i<512;i++)str=str+szBuf[i]; if(str=="exit") { return 0; } return 1; } void chanel_pipe::write_chanel(char string_ch[20]) { if(!hNamedPipe) { // Создаем канал с процессом PIPES hNamedPipe = CreateFile( L"\\\\.\\pipe\\$MyPipe$", GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
// Если возникла ошибка, выводим ее код и // завершаем работу приложения if(hNamedPipe == INVALID_HANDLE_VALUE) { fprintf(stdout,"CreateFile: Error %ld\n", GetLastError()); //getch(); } else WriteFile(hNamedPipe, string_ch, strlen(string_ch) + 1, &cbWritten, NULL); } else WriteFile(hNamedPipe, string_ch, strlen(string_ch) + 1, &cbWritten, NULL); } void chanel_pipe::slot_read() { bool rr=false; if(hNamedPipe) rr=read_chanel(); } void chanel_pipe::run() {
hEndWrite=CreateEvent(NULL,FALSE,FALSE,NULL); OVL.Offset=0; OVL.OffsetHigh=0; OVL.hEvent=hEndWrite; //bool PRezWait=WaitNamedPipe( L"\\\\.\\pipe\\$MyPipe$", NMPWAIT_WAIT_FOREVER ); while(!hNamedPipe) { // Создаем канал с процессом PIPES hNamedPipe=CreateFile( L"\\\\.\\pipe\\$MyPipe$", GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING,FILE_FLAG_OVERLAPPED, NULL);
// Если возникла ошибка, выводим ее код и // завершаем работу приложения if(hNamedPipe == INVALID_HANDLE_VALUE) { fprintf(stdout,"CreateFile: Error %ld\n", GetLastError()); } } Ttime=new QTimer; connect(Ttime,SIGNAL(timeout()),this,SLOT(slot_read())); Ttime->start(50); exec(); } // запускаю из основного процесса ch_pipe=new chanel_pipe(); ch_pipe->start(); //
|