Форум программистов, компьютерный форум, киберфорум
Наши страницы

C++ и сети

Войти
Регистрация
Восстановить пароль
 
 
Рейтинг: Рейтинг темы: голосов - 20, средняя оценка - 4.75
Yoshi21
0 / 0 / 0
Регистрация: 25.11.2012
Сообщений: 30
#1

Передача данных по Анонимным (Неименованым) каналам с последующим использованием этих данных - C++

14.05.2013, 21:14. Просмотров 2762. Ответов 36
Метки нет (Все метки)

Всем доброго времени суток. Нужна помощь:
Имеется Сервер и Клиент связанные анонимным каналом. Через анонимный канал нужно передать 4 значения, которые в дальнейшем на сервере протабулируются. Вот пытался это организовать не получилось. Помогите разобраться. Заранее спасибо.
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
//клиент
#include <iostream>
#include <windows.h>
 
using namespace std;
 
int main()
{
    int szBuf[4];
    srand(GetCurrentProcessId());
 
    //"открываем" событие, созданное сервером
    HANDLE hEv = CreateEventA(0, TRUE, FALSE, "READEVENT");
 
    szBuf[0]=(rand()%5)+1;
    szBuf[1]=(szBuf[0]+rand()%20)*2;
    szBuf[2]=rand()%5;
    szBuf[3]=rand()%5;
 
    //пишем в канал (дескриптор вывода переопределен в коде создание процесса в сервере
    std::cout<<"Hi, i'm client\0"<<endl;
    for (int i=0;i<4;i++)
        std::cout<<szBuf[i]<<endl;
    //информируем сервер о готовности данных для чтения
    SetEvent(hEv);
 
    CloseHandle(hEv);
 
    return 0;
}
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
//сервер
#include <iostream>
#include <windows.h>
#include <stdio.h>
#include <conio.h>
#include <fstream>
#include <cmath>
using namespace std;
 
void tab(int start, int end, int step, int funcnum)
{
    ofstream file("ResultFile.txt",ios_base::app);
    if(start>end)
        swap(start,end);
    if(step==0)
        step++;
    switch(funcnum)
    {
    case 0:
        file<<"Крок: "<<step<<", Початкове значення: "<<start<<", Kiнцеве значення: "<<end<<" функція sin(x) має значення:\n";
        for(int i=start;i<end;i+=step)
        {
            file<<sin(i)<<"\t";
        }
        file<<"\n\n";
        break;
    case 1:
        file<<"Крок: "<<step<<", Початкове значення: "<<start<<", Kiнцеве значення: "<<end<<" функція cos(x) має значення:\n";
        for(int i=start;i<end;i+=step)
        {
            file<<cos(i)<<"\t";
        }
        file<<"\n\n";
        break;
    case 2:
        file<<"Крок: "<<step<<", Початкове значення: "<<start<<", Kiнцеве значення: "<<end<<" функція tg(x) має значення:\n";
        for(int i=start;i<end;i+=step)
        {
            file<<tan(i)<<"\t";
        }
        file<<"\n\n";
        break;
    case 3:
        file<<"Крок: "<<step<<", Початкове значення: "<<start<<", Kiнцеве значення: "<<end<<" функція ctg(x) має значення:\n";
        for(int i=start;i<end;i+=step)
        {
            file<<1/tan(i)<<"\t";
        }
        file<<"\n\n";
        break;
    default:
        file<<"Крок: "<<step<<", Початкове значення: "<<start<<", Kiнцеве значення: "<<end<<" функція 1/x має значення:\n";
        for(int i=start;i<end;i+=step)
        {
            file<<1.0/i<<"\t";
        }
        file<<"\n\n";
    }
    file.close();
}
 
int main()
{
    HANDLE hRead = INVALID_HANDLE_VALUE;
    HANDLE hWrite = INVALID_HANDLE_VALUE;
 
    int szBuf[4];
 
    SECURITY_ATTRIBUTES sa = {sizeof(sa)};
    sa.bInheritHandle = TRUE; //хэндлы наследуемые
    sa.lpSecurityDescriptor = NULL;
 
    //создаем анонимный канал
    if(!CreatePipe(&hRead, &hWrite, &sa, 0))
    {
        std::cout<<"Error code: "<<GetLastError()<<std::endl;
        return -1;
    }
 
    //событие для информирования о доступности чтения
    HANDLE hEv = CreateEventA(0, TRUE, FALSE, "READEVENT");
 
    STARTUPINFOA si = {sizeof(si)};
 
    //передаем хэндлы в процесс-клиент
    si.hStdOutput = hWrite;
    si.hStdInput = hRead;
    si.hStdError = hWrite;
 
    //говорим о необходимости переопределения стандартных дескрипторов
    si.dwFlags = STARTF_USESTDHANDLES;
 
    PROCESS_INFORMATION pi = {0};
 
    //запускаем процесс-клиент
    if(!CreateProcessA(NULL, "CLIENT.exe", NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi ))
    {
        std::cout<<"Error code: "<<GetLastError()<<std::endl;
        CloseHandle(hRead);
        CloseHandle(hWrite);
        CloseHandle(hEv);
        return -1;
    }
    CloseHandle(pi.hProcess);
    CloseHandle(pi.hThread);
 
    //ждем пока клиент запишет данные
    WaitForSingleObject(hEv, INFINITE);
 
    DWORD readed = 0;
    BYTE buf[255] = {0};
 
    //читаем данные из канала и выводим их (в данном случае будет строка)
    if(ReadFile(hRead, buf, 255, &readed, NULL))
    {
        std::cout<<"Read from pipe:"<< (char*)buf<<std::endl;system("PAUSE");
    }
 
    for (int i=0;i<4;i++)
        std::cout<<szBuf<<endl;
 
    tab(szBuf[0],szBuf[1],szBuf[2],szBuf[3]);
 
    CloseHandle(hRead);
    CloseHandle(hWrite);
    CloseHandle(hEv);
 
    return 0;
}
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
14.05.2013, 21:14
Я подобрал для вас темы с готовыми решениями и ответами на вопрос Передача данных по Анонимным (Неименованым) каналам с последующим использованием этих данных (C++):

Передача данных по каналам - Assembler
Доброго времени суток. Подскажите пожалуйста как принять данные из клавиатуры и передать их в канал? Когда создаю канал, у меня вылетает...

запуск и передача данных сторонней программе с последующим возвратом результата в PHP - PHP
exec() запускает и возвращает результат, а как еще и передать данные в саму программу?

Вывод всех записей из БД и передача этих данных JS-скрипту - PHP БД
ПОМОГИТЕ ПОЖАЛУЙСТА! есть вот такой вывод php &lt;?php $sql = 'SELECT * FROM statist WHERE user_id = '.$us_id.' order by id DESC'; ...

Выбор данных из полей со списком, занесение этих данных в список и добавление данных в таблицу - MS Access
Подскажите пожалуйста, как что то подобное сделать в Access или посоветуйте хорошую литературу где это описывается.

Передача данных с использованием getJSON - JavaScript
Доброго времени суток. Создаю скрипт динамических списков для выбора сначала области, затем, в зависимости от выбранной области...

Передача данных с использованием SocketChannel - Java Сети
При регистрации селектором нового соединения создаем SocketChannel, устанавливаем его в неблокирующий режим, регистрируем его в том же...

36
Убежденный
Ушел с форума
Эксперт С++
15937 / 7247 / 1140
Регистрация: 02.05.2013
Сообщений: 11,637
Записей в блоге: 1
Завершенные тесты: 1
15.05.2013, 11:11 #2
Попробуйте свести код к минимальному примеру: создание дочернего процесса с
подменой стандартного вывода в пайп, чтение из пайпа и отображение результата.
Так будет понятно, в каком месте ошибка.

Канонический пример:
Creating a Child Process with Redirected Input and Output

На что стоит обратить внимание:

C++
1
2
3
4
5
6
7
//событие для информирования о доступности чтения
HANDLE hEv = CreateEventA(0, TRUE, FALSE, "READEVENT");
 
...
 
//ждем пока клиент запишет данные
WaitForSingleObject(hEv, INFINITE);
Использовать события для ожидания готовности дочернего процесса - ненадежно.
Если дочерний процесс неожиданно завершится, например, в результате ошибки
или пользователем через диспетчер задач, то выход из функции ожидания
никогда не произойдет.



C++
1
std::cout<<"Error code: "<<GetLastError()<<std::endl;
Нет никакой гарантии того, что GetLastError будет вызвана до вывода "Error code", и
нет гарантии, что вывод "Error code:" не изменит last error.
Правильно так:
C++
1
2
DWORD const LastError = GetLastError();
std::cout << "Error code: " << LastError << std::endl;


C++
1
2
3
4
5
6
7
8
9
STARTUPINFOA si = {sizeof(si)};
 
//передаем хэндлы в процесс-клиент
si.hStdOutput = hWrite;
si.hStdInput = hRead;
si.hStdError = hWrite;
 
//говорим о необходимости переопределения стандартных дескрипторов
si.dwFlags = STARTF_USESTDHANDLES;
Во-первых, не указано значения поля "cb" (длина структуры si).
Во-вторых, структуру STARTUPINFO лучше не заполнять вручную, а наследовать параметры,
заданные для текущего процесса, после чего подкорректировать ее содержимое в
соответствии со своими замыслами. См. функцию GetStartupInfo.
В-третьих, если вы подменяете хэндлы стандартных потоков, то должны использовать
разные устройства (пайпы), а не одно и то же. Как минимум, должно быть два пайпа -
один для hStdInput и второй для hStdOutput/hStdError.



C++
1
2
//запускаем процесс-клиент
if(!CreateProcessA(NULL, "CLIENT.exe", NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi ))
В данном конкретном случае этот код корректный.
Но Unicode-версии функций CreateProcessXXXX могут изменять буфер с командной строкой,
об этом явно сказано в документации. А строковые литералы в C/C++ константны.
Поэтому надежнее так:
C++
1
2
3
4
// Массив допускает перезапись, в отличие от строковых литералов.
char pCmdLine[] = {"CLIENT.exe"};
 
if(!CreateProcessA(NULL, &pCmdLine[0], NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi ))
1
Yoshi21
0 / 0 / 0
Регистрация: 25.11.2012
Сообщений: 30
15.05.2013, 15:26  [ТС] #3
Спасибо за советы и помощь буду разбираться, есть ещё 1 вопрос: как правильно передать на сервер интовский массив чисел?
Вот получается на клиенте массив
C++
1
int szBuf[4];
Вычесляю значения и передаю на сервер
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
 
    srand(GetCurrentProcessId());
    HANDLE hEv = CreateEventA(0, TRUE, FALSE, "READEVENT");
 
    szBuf[0]=(rand()%5)+1;
    szBuf[1]=(szBuf[0]+rand()%20)*2;
    szBuf[2]=rand()%5;
    szBuf[3]=rand()%5;
 
    std::cout<<"Hi, i'm client\0"<<endl;
    for (int i=0;i<4;i++)
        std::cout<<szBuf[i]<<endl;
 
    SetEvent(hEv);
 
    CloseHandle(hEv);
Вот читаю на сервере данные из канала
C++
1
2
3
4
5
6
7
8
    DWORD readed = 0;
    BYTE buf[255] = {0};
 
//читаем данные из канала и выводим их 
    if(ReadFile(hRead, buf, 255, &readed, NULL))
    {
        std::cout<<"Read from pipe:"<< (char*)buf<<std::endl;system("PAUSE");
    }
(в консоль вывело 4 значения )Но получается я просто прочитал строку, мне же нужно дальше работать на сервере с этими 4 значениями. Объясните пожалуйста как передать этот szBuf[4].Спасибо.
0
Убежденный
Ушел с форума
Эксперт С++
15937 / 7247 / 1140
Регистрация: 02.05.2013
Сообщений: 11,637
Записей в блоге: 1
Завершенные тесты: 1
15.05.2013, 16:49 #4
Здесь получается, что клиент передает числовые данные, преобразуя их в символьную строку.
Значит, сервер должен выполнить обратную операцию - преобразовать строку в числа.
Но еще лучше сразу передавать числа, только не через std::cout, а напрямую в пайп, с
помощью WriteFile.
1
Yoshi21
0 / 0 / 0
Регистрация: 25.11.2012
Сообщений: 30
15.05.2013, 19:34  [ТС] #5
Цитата Сообщение от Убежденный Посмотреть сообщение
Но еще лучше сразу передавать числа, только не через std::cout, а напрямую в пайп, с
помощью WriteFile.
Последовав Вашему совету попробовал это организовать с помощью WriteFile. Но увы теперь оно вообще не передает.

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
//клиент
#include <iostream>
#include <conio.h>
#include <windows.h>
 
using namespace std;
 
int main()
{
    int szBuf[4];
    srand(GetCurrentProcessId());
 
    HANDLE hWritePipe;
 
    //"открываем" событие, созданное сервером
    HANDLE hEv = CreateEventA(0, TRUE, FALSE, "READEVENT");
 
    szBuf[0]=(rand()%5)+1;
    szBuf[1]=(szBuf[0]+rand()%20)*2;
    szBuf[2]=rand()%5;
    szBuf[3]=rand()%5;
 
    // преобразуем символьное представление дескриптора в число
    hWritePipe = (HANDLE)atoi;
    DWORD dwBytesWritten;
    if(!WriteFile(
                hWritePipe,
                &szBuf,
                sizeof(szBuf),
                &dwBytesWritten,
                NULL)){
    std::cout<<"Error code: "<<GetLastError()<<std::endl;}
 
    CloseHandle(hWritePipe);
 
    SetEvent(hEv);
 
    CloseHandle(hEv);
 
    return 0;
}
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
//сервер
#include <iostream>
#include <windows.h>
#include <stdio.h>
#include <conio.h>
#include <fstream>
#include <cmath>
using namespace std;
 
void tab(int start, int end, int step, int funcnum){...}
 
int main()
{
    int szBuf[4];
    
    SECURITY_ATTRIBUTES sa = {sizeof(sa)};
    sa.bInheritHandle = TRUE; 
    sa.lpSecurityDescriptor = NULL;
    
    HANDLE hReadPipe, hWritePipe;
    
    //создаем анонимный канал
    if(!CreatePipe(&hReadPipe, &hWritePipe, NULL, 0))
    {
        std::cout<<"Error code: "<<GetLastError()<<std::endl;
        return -1;
    }
    
    CloseHandle(hWritePipe);
    
    HANDLE hEv = CreateEventA(0, TRUE, FALSE, "READEVENT");//событие для информирования о доступности чтения
    
    STARTUPINFOA si = {sizeof(si)};
    
    
    si.dwFlags = STARTF_USESTDHANDLES;//говорим о необходимости переопределения стандартных дескрипторов
    
    PROCESS_INFORMATION pi = {0};
    
    //запускаем процесс-клиент
    if(!CreateProcessA(NULL, "CLIENT.exe", NULL, NULL, TRUE, CREATE_NEW_CONSOLE, NULL, NULL, &si, &pi ))
    {
        std::cout<<"Error code: "<<GetLastError()<<std::endl;
        return -1;
    }
    
    CloseHandle(pi.hProcess);
    CloseHandle(pi.hThread);
    
    WaitForSingleObject(hEv, INFINITE);
    
    int nData=0;
    DWORD dwBytesRead;
    ReadFile(
                hReadPipe,
                &nData,
                sizeof(nData),
                &dwBytesRead,
                NULL);
    
    tab(szBuf[0],szBuf[1],szBuf[2],szBuf[3]);
    
    CloseHandle(hEv);
    CloseHandle(hReadPipe);
    
    return 0;
}
0
Убежденный
Ушел с форума
Эксперт С++
15937 / 7247 / 1140
Регистрация: 02.05.2013
Сообщений: 11,637
Записей в блоге: 1
Завершенные тесты: 1
15.05.2013, 19:58 #6
C++
1
2
// преобразуем символьное представление дескриптора в число
hWritePipe = (HANDLE)atoi;
А это вообще компилируется ?



C++
1
2
3
4
5
6
7
8
//создаем анонимный канал
if(!CreatePipe(&hReadPipe, &hWritePipe, NULL, 0))
{
    std::cout<<"Error code: "<<GetLastError()<<std::endl;
    return -1;
}
    
CloseHandle(hWritePipe);
Хэндл закрывается преждевременно, дочерний процесс не успевает его унаследовать.
Эту функцию нужно вызывать уже после создания процесса.



C++
1
2
STARTUPINFOA si = {sizeof(si)};
si.dwFlags = STARTF_USESTDHANDLES;//говорим о необходимости переопределения стандартных дескрипторов
А сами дескрипторы где ?



C++
1
2
3
4
5
6
//запускаем процесс-клиент
if(!CreateProcessA(NULL, "CLIENT.exe", NULL, NULL, TRUE, CREATE_NEW_CONSOLE, NULL, NULL, &si, &pi ))
{
    std::cout<<"Error code: "<<GetLastError()<<std::endl;
    return -1;
}
Флаг CREATE_NEW_CONSOLE здесь лишний.
0
Yoshi21
0 / 0 / 0
Регистрация: 25.11.2012
Сообщений: 30
15.05.2013, 21:05  [ТС] #7
Цитата Сообщение от Убежденный Посмотреть сообщение
C++
1
2
// преобразуем символьное представление дескриптора в число
hWritePipe = (HANDLE)atoi;
А это вообще компилируется ?



C++
1
2
3
4
5
6
7
8
//создаем анонимный канал
if(!CreatePipe(&hReadPipe, &hWritePipe, NULL, 0))
{
    std::cout<<"Error code: "<<GetLastError()<<std::endl;
    return -1;
}
    
CloseHandle(hWritePipe);
Хэндл закрывается преждевременно, дочерний процесс не успевает его унаследовать.
Эту функцию нужно вызывать уже после создания процесса.



C++
1
2
STARTUPINFOA si = {sizeof(si)};
si.dwFlags = STARTF_USESTDHANDLES;//говорим о необходимости переопределения стандартных дескрипторов
А сами дескрипторы где ?



C++
1
2
3
4
5
6
//запускаем процесс-клиент
if(!CreateProcessA(NULL, "CLIENT.exe", NULL, NULL, TRUE, CREATE_NEW_CONSOLE, NULL, NULL, &si, &pi ))
{
    std::cout<<"Error code: "<<GetLastError()<<std::endl;
    return -1;
}
Флаг CREATE_NEW_CONSOLE здесь лишний.
Компилируется (использовал пример с "Системное програмирование в Windows" А.Побегайло), более того создается анонимный канал, даже запускается клиент но увы не отсылает данные.
C++
1
 std::cout<<"Error code: "<<GetLastError()<<std::endl;
Гетластерор указывает на код ошибки 6. Погуглив понял что что-то с хендлами не знаю правда что именно

Добавлено через 11 минут
А нет, выскакивает пустое окошко и всё =/

Добавлено через 30 минут
Убежденный,
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
//сервер
#include <iostream>
#include <windows.h>
#include <stdio.h>
#include <conio.h>
#include <fstream>
#include <cmath>
using namespace std;
 
void tab(int start, int end, int step, int funcnum){...}
 
int main()
{
    int szBuf[4];
 
    SECURITY_ATTRIBUTES sa = {sizeof(sa)};
    sa.bInheritHandle = TRUE; //хэндлы наследуемые
    sa.lpSecurityDescriptor = NULL;
 
    HANDLE hReadPipe, hWritePipe;
 
    //создаем анонимный канал
    if(!CreatePipe(&hReadPipe, &hWritePipe, NULL, 0))
    {
        std::cout<<"Error code: "<<GetLastError()<<std::endl;
        return -1;
    }
        CloseHandle(hWritePipe);
    HANDLE hEv = CreateEventA(0, TRUE, FALSE, "READEVENT");//событие для информирования о доступности чтения
 
    STARTUPINFOA si = {sizeof(si)};
 
 
    si.dwFlags = STARTF_USESTDHANDLES;//говорим о необходимости переопределения стандартных дескрипторов
 
    PROCESS_INFORMATION pi = {0};
 
    //запускаем процесс-клиент
    if(!CreateProcessA(NULL, "CLIENT.exe", NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi ))
    {
        std::cout<<"Error code: "<<GetLastError()<<std::endl;
        return -1;
    }
 
    CloseHandle(pi.hProcess);
    CloseHandle(pi.hThread);
 
    WaitForSingleObject(hEv, INFINITE);
 
    //int nData=0;
    DWORD dwBytesRead;
    ReadFile(
                hReadPipe,
                &szBuf,
                sizeof(szBuf),
                &dwBytesRead,
                NULL);
    cout<<"Peredalo"<<endl;
 
    for (int i=0;i<4;i++)
           std::cout<<szBuf[i]<<endl;
 
    tab(szBuf[0],szBuf[1],szBuf[2],szBuf[3]);
 
    CloseHandle(hEv);
    CloseHandle(hReadPipe);
 
    return 0;
}
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
//клиент
#include <iostream>
#include <conio.h>
#include <windows.h>
 
using namespace std;
 
int main()
{
    int szBuf[4];
    srand(GetCurrentProcessId());
 
    HANDLE hWritePipe;
 
    //"открываем" событие, созданное сервером
    HANDLE hEv = CreateEventA(0, TRUE, FALSE, "READEVENT");
 
    szBuf[0]=(rand()%5)+1;
    szBuf[1]=(szBuf[0]+rand()%20)*2;
    szBuf[2]=rand()%5;
    szBuf[3]=rand()%5;
 
    // преобразуем символьное представление дескриптора в число
    //hWritePipe = (HANDLE)atoi;
    DWORD dwBytesWritten;
    if(!WriteFile(
                hWritePipe,
                &szBuf,
                sizeof(szBuf),
                &dwBytesWritten,
                NULL)){
    std::cout<<"Error code: "<<GetLastError()<<std::endl;}
 
    CloseHandle(hWritePipe);
 
    SetEvent(hEv);
 
    CloseHandle(hEv);
 
    return 0;
}
Скомпилило, вывело массив - четыре 0, соответственно прихожу к мислы, что не передало. Hикаких ошибок не выдало.
0
Убежденный
Ушел с форума
Эксперт С++
15937 / 7247 / 1140
Регистрация: 02.05.2013
Сообщений: 11,637
Записей в блоге: 1
Завершенные тесты: 1
15.05.2013, 21:25 #8
Клиент у Вас работает с неинициализированным хэндлом hWritePipe:
C++
1
2
3
4
5
6
7
8
9
10
HANDLE hWritePipe;
 
// ...
 
if(!WriteFile(
    hWritePipe,
    &szBuf,
    sizeof(szBuf),
    &dwBytesWritten,
    NULL))
Нужно или вызвать GetStartupInfo и брать оттуда hStdOutput, либо
вызывать GetStdHandle(STD_OUTPUT_HANDLE) и использовать полученный
хэндл для записи данных в клиенте.
1
Yoshi21
0 / 0 / 0
Регистрация: 25.11.2012
Сообщений: 30
15.05.2013, 22:13  [ТС] #9
Цитата Сообщение от Убежденный Посмотреть сообщение
Клиент у Вас работает с неинициализированным хэндлом hWritePipe:
C++
1
2
3
4
5
6
7
8
9
10
HANDLE hWritePipe;
 
// ...
 
if(!WriteFile(
    hWritePipe,
    &szBuf,
    sizeof(szBuf),
    &dwBytesWritten,
    NULL))
Нужно или вызвать GetStartupInfo и брать оттуда hStdOutput, либо
вызывать GetStdHandle(STD_OUTPUT_HANDLE) и использовать полученный
хэндл для записи данных в клиенте.
На сколько я понял это делается вот так?
C++
1
2
3
//сервер
  STARTUPINFOA si = {sizeof(si)};
  si.hStdOutput=hWritePipe;
0
Убежденный
Ушел с форума
Эксперт С++
15937 / 7247 / 1140
Регистрация: 02.05.2013
Сообщений: 11,637
Записей в блоге: 1
Завершенные тесты: 1
15.05.2013, 22:48 #10
Наоборот.
Клиент ничего не должен писать в STARTUPINFO, он должен получить
хэндл стандартного вывода (который был подменен серверным процессом на пайп).
Делается это либо вызовом GetStdHandle(STD_OUTPUT_HANDLE), либо с помощью
GetStartupInfo - нужный хэндл будет лежать в STARTUPINFO.hStdOutput.
0
Yoshi21
0 / 0 / 0
Регистрация: 25.11.2012
Сообщений: 30
15.05.2013, 22:54  [ТС] #11
Убежденный, я запутался. Если Вам не трудно, можете написать пару строк кода как это должно выглядеть?
0
Убежденный
Ушел с форума
Эксперт С++
15937 / 7247 / 1140
Регистрация: 02.05.2013
Сообщений: 11,637
Записей в блоге: 1
Завершенные тесты: 1
15.05.2013, 23:33 #12
Мне не трудно, но Вы уверены, что в этом есть смысл ?
Может, стоит попробовать более простые примеры ?
0
Yoshi21
0 / 0 / 0
Регистрация: 25.11.2012
Сообщений: 30
15.05.2013, 23:41  [ТС] #13
Убежденный, тогда помогите пожалуйста.
0
Убежденный
Ушел с форума
Эксперт С++
15937 / 7247 / 1140
Регистрация: 02.05.2013
Сообщений: 11,637
Записей в блоге: 1
Завершенные тесты: 1
16.05.2013, 00:37 #14
Пример использования пайпа для перенаправления стандартного вывода.
Обработка ошибок опущена для наглядности.

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
//---------------------
//
//    S E R V E R
//
//---------------------
 
 
 
#include <iostream>
#include <Windows.h>
 
 
 
int main()
{
    using namespace std;
 
    // Создаем пайп.
    // Хэндлы пайпа должны быть наследуемыми.
    // Точнее говоря, в данном примере лишь один хэндл должен
    // быть наследуемым, но это сейчас несущественно.
 
    SECURITY_ATTRIBUTES sa;
    sa.bInheritHandle = TRUE;
    sa.lpSecurityDescriptor = NULL;
    sa.nLength = sizeof (sa);    
 
    HANDLE hReadPipe;
    HANDLE hWritePipe;    
 
    CreatePipe(&hReadPipe, &hWritePipe, &sa, 0);
 
    // Заполняем структуру STARTUPINFO для будущего процесса.
    // Подменяем хэндл стандартного вывода на хэндл записи в пайп.
 
    STARTUPINFOW si;
    GetStartupInfoW(&si);
 
    si.dwFlags |= STARTF_USESTDHANDLES;
    si.hStdOutput = hWritePipe;
 
    // Запускаем дочерний процесс.
 
    PROCESS_INFORMATION pi;
 
    wchar_t pCmdLine[] = {L"client.exe"}; // Буфер должен быть изменяемым !
 
    CreateProcessW(NULL,
        pCmdLine,
        NULL,
        NULL,
        TRUE, // <--- Наследовать хэндлы ? Да.
        NORMAL_PRIORITY_CLASS,
        NULL,
        NULL,
        &si,
        &pi);
 
    CloseHandle(pi.hProcess);
    CloseHandle(pi.hThread);
 
    // Закрываем хэндл записи - нам он не нужен, а у
    // дочернего процесса уже есть его копия.
 
    CloseHandle(hWritePipe);
 
    // Выделяем буфер достаточного размера, чтобы принять все данные.
 
    DWORD const BuffSize = 100;
    byte *pBuffer = new byte[BuffSize];
 
    // Читаем из пайпа, пока на том конце не завершат запись или
    // пока буфер не будет заполнен.
 
    DWORD nBytes;
 
    ReadFile(hReadPipe, pBuffer, BuffSize, &nBytes, NULL);
    CloseHandle(hReadPipe);
 
    // Получаем int-переменную из буфера и выводим ее на экран.
 
    int const Value = *((int const *)pBuffer);
 
    cout << "Value = " << Value << endl;
 
    // Очистка ресурсов и выход.
 
    delete [] pBuffer;
 
    return EXIT_SUCCESS;
}


C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
//---------------------
//
//    C L I E N T
//
//---------------------
 
 
 
#include <iostream>
#include <Windows.h>
 
 
 
int main()
{
    using namespace std;
 
    // Получаем хэндл стандартного вывода.
    // Обычно здесь хэндл консоли, но сейчас серверный
    // процесс подменил его на хэндл пайпа.
    //
    // Альтернатива:
    //
    // STARTUPINFO si;
    // GetStartupInfoW(&si);
    // HANDLE const hStdOutput = si.hStdOutput;
 
    HANDLE const hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
 
    // Записываем в устройство переменную типа int.
 
    int const Value = 123;
 
    DWORD nBytes;
    WriteFile(hStdOutput, &Value, sizeof (Value), &nBytes, NULL);
 
    return EXIT_SUCCESS;
}


Вывод:
> Value = 123
2
Yoshi21
0 / 0 / 0
Регистрация: 25.11.2012
Сообщений: 30
16.05.2013, 15:49  [ТС] #15
Убежденный, огромное спасибо за ваш пример! Чуть-чуть его модифицируя я сумел передать массив. Собственно вот:

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
//---------------------
//
//    C L I E N T
//
//---------------------
 
#include <iostream>
#include <Windows.h>
 
int main()
{
    using namespace std;
    srand(GetCurrentProcessId());
 
    // Получаем хэндл стандартного вывода.
    // Обычно здесь хэндл консоли, но сейчас серверный
    // процесс подменил его на хэндл пайпа.
    //
    // Альтернатива:
    //
    // STARTUPINFO si;
    // GetStartupInfoW(&si);
    // HANDLE const hStdOutput = si.hStdOutput;
 
 
    HANDLE const hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
 
    // Записываем в устройство переменную типа int.
    int szBuf[4]={0,0,0,0};
    szBuf[0]=(rand()%5)+1;
    szBuf[1]=(szBuf[0]+rand()%20)*2;
    szBuf[2]=rand()%5;
    szBuf[3]=rand()%5;
 
    DWORD nBytes;
 
    WriteFile(hStdOutput, &szBuf, sizeof (szBuf), &nBytes, NULL);
    return EXIT_SUCCESS;
}
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
//---------------------
//
//    S E R V E R
//
//---------------------
 
#include <iostream>
#include <Windows.h>
#include <stdio.h>
#include <conio.h>
#include <fstream>
#include <cmath>
using namespace std;
 
void tab(int start, int end, int step, int funcnum){...}
 
int main()
{
    // Создаем пайп.
    // Хэндлы пайпа должны быть наследуемыми.
    // Точнее говоря, в данном примере лишь один хэндл должен
    // быть наследуемым, но это сейчас несущественно.
    SECURITY_ATTRIBUTES sa;
    sa.bInheritHandle = TRUE;
    sa.lpSecurityDescriptor = NULL;
    sa.nLength = sizeof (sa);
 
    HANDLE hReadPipe;
    HANDLE hWritePipe;
 
    CreatePipe(&hReadPipe, &hWritePipe, &sa, 0);
 
    // Заполняем структуру STARTUPINFO для будущего процесса.
    // Подменяем хэндл стандартного вывода на хэндл записи в пайп.
 
    STARTUPINFOW si;
    GetStartupInfoW(&si);
 
    si.dwFlags |= STARTF_USESTDHANDLES;
    si.hStdOutput = hWritePipe;
 
    // Запускаем дочерний процесс.
 
    PROCESS_INFORMATION pi;
 
    wchar_t pCmdLine[] = {L"cli.exe"}; // Буфер должен быть изменяемым !
 
    CreateProcessW(NULL,
        pCmdLine,
        NULL,
        NULL,
        TRUE, // <--- Наследовать хэндлы ? Да.
        NORMAL_PRIORITY_CLASS,
        NULL,
        NULL,
        &si,
        &pi);
 
    CloseHandle(pi.hProcess);
    CloseHandle(pi.hThread);
 
    // Закрываем хэндл записи - нам он не нужен, а у
    // дочернего процесса уже есть его копия.
 
    CloseHandle(hWritePipe);
 
    // Выделяем буфер достаточного размера, чтобы принять все данные.
 
 
    // Читаем из пайпа, пока на том конце не завершат запись или
    // пока буфер не будет заполнен.
 
    DWORD nBytes;
    int szBuf[4]={0,0,0,0};
    int i=0;
 
    ReadFile(hReadPipe,szBuf,sizeof(szBuf),&nBytes, NULL);
    CloseHandle(hReadPipe);
 
    // Получаем int-переменную из буфера и выводим ее на экран.
   
    for (int i=0;i<4;i++)
           cout<<szBuf[i]<<endl;
 
    tab(szBuf[0],szBuf[1],szBuf[2],szBuf[3]);
    // Очистка ресурсов и выход.
 
    return EXIT_SUCCESS;
}
Меня заинтересовало, а как их синхронизировать при помощи мьютексов?
0
16.05.2013, 15:49
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
16.05.2013, 15:49
Привет! Вот еще темы с ответами:

Передача данных с использованием Intent - Программирование Android
Добрый день! Не получается перенести текст введённый с одного активити в другой. Код первого активити: Intent intent = new...

Передача данных с использованием Html.BeginForm - C# MVC
Привет друзья. У нас есть страничка Page. @{ int a = 7; } @using (Html.BeginForm(&quot;funk&quot;, &quot;PageTest&quot;, FormMethod.Post, new { enctype...

Передача данных с использованием протокола UDP - C#
Всем добра. Владею вб и пхп на хорошо. Но не очень дружу с сшарп. Нужен самый простой пример отправки данных в виде текста на другой...

Передача данных с формы на форму с использованием класса - C#
Добрый день, уважаемые формучане! Хочу сразу же извиниться если не в том разделе пишу. Итак, уже вторые сутки маюсь, не могу никак...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
15
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2018, vBulletin Solutions, Inc.
Рейтинг@Mail.ru