Наши проекты:
Журнал · Discuz!ML · Wiki · DRKB · Помощь проекту |
||
ПРАВИЛА | FAQ | Помощь | Поиск | Участники | Календарь | Избранное | RSS |
[18.188.44.223] |
|
Страницы: (4) 1 2 [3] 4 все ( Перейти к последнему сообщению ) |
Сообщ.
#31
,
|
|
|
Спасибо, отлично.
Максимально упростил свой код, чтобы оценить возможность. Чтобы написать оперативную прогу, буду ориентироваться на твой подход, который считаю совершенно верным. |
Сообщ.
#32
,
|
|
|
Цитата vlad2 @ Как выполнять команды и читать из командной строки консольного приложения без закрытия самого приложения? Спасибо. Начнем с того, что термин "конвеер" (pipe) - это однонаправленный канал межпроцессного взаимодействия. Таким образом, одна программа пишет в STDOUT, вторая программа читает из STDIN, и что-то делает. Что делать чтобы вторая программа не закрывалась? Ответ простой - читать STDIN в бесконечном цикле, с возможностью выхода по условию. Увы, но не к сожалению, я Питона не знаю, приведу пример на Перле: first.pl #/usr/local/bin/perl $| = 1; # flush сразу после очередной операции I/O print "print 1;\n"; print "print 2;\n"; sleep(2); print "print 3;\n"; sleep(4); print "print 4;\n"; print "EXIT\n"; next.pl #/usr/local/bin/perl $| = 1; # flush сразу после очередной операции I/O while(1) { $in = <STDIN>; last if ($in =~ /^EXIT\s*$/); eval($in); } Тест запускаем так: perl first.pl | perl next.pl В результате первые две команды будут прочитаны и сразу выполнены - выведутся два числа 1 и 2. Потом задержка. Потом вывод числа 3. Потом еще одна задержка. Потом вывод числа 4 и вторая программа "ловит" условие выхода "EXIT", и выполнение завершается. Сценарий интерпретаторов, что Перла, что Питона - одинаков. Выполнить скрипт и завершится. Вот Перлу приходит на помощь функция eval(), которая выполняет как код переданную ей строку в качестве аргумента. Может ли такое Питон - я не знаю. Далее. Если нужен двусторонний обмен, вангую - нужно определить два именованных пайпа. Для одной программы один канал для записи, второй для чтения. Для второй программы каналы меняются местами. Тогда взаимодействие программ не будет зависеть на каком из терминалов запущены программы. |
Сообщ.
#33
,
|
|
|
Спасибо, JoeUser. Питона тоже не знаю. Мне нужно из внешней программы периодически (не одним скриптом) давать команды Питону и читать его ответы, если они есть. Питон во время всех этих действий должен находиться в памяти. Тоже создаю два пайпа, как написано во многих примерах, правда анонимных...
|
Сообщ.
#34
,
|
|
|
Цитата vlad2 @ Питона тоже не знаю. Ну сверскоростное гугление говорит, что eval() в Питоне есть. Так что "принимающий скрипт" можешь писать по образу и подобию моего next.pl, и Питон будет висеть в памяти и читать что ему определишь. А вот для ответов делай именованный пайп. |
Сообщ.
#35
,
|
|
|
Кстати да, а попробуй именованные.
|
Сообщ.
#36
,
|
|
|
Цитата JoeUser @ Вроде, для чтения использую PeekNamedPipe, как во многих примерах. для ответов делай именованный пайп |
Сообщ.
#37
,
|
|
|
я несколько подправил класс "cmdShell", и максимально возможно выполнил
его внутренности в стиле твоей программы. В итоге получилось так: #include "cmdShell_b.h" bool WriteToPython(cmdShell_b& cSh, const char* pStr) { bool bRetC=false; size_t sizeWr = strlen(pStr); if(sizeWr) { if(!cSh.WriteToPipe (pStr,sizeWr)) return false; } MEMT<char> buf; bRetC = cSh.ReadFromPipe (buf); size_t size = buf.GetDataSize(); if((bRetC)&&(size)) { for(size_t i=0;i<size;++i) { _tprintf(_T("%c"),buf[i]); } } _tprintf(_T("\n")); return bRetC; } // -------------------------------------------------------------------------- int __cdecl _tmain(int argc, char **argv) { _tprintf(_T("\tHello, world!\n")); cmdShell_b cSh; bool bRetC = cSh.Install(_T("python -i")); if(bRetC) { WriteToPython(cSh, ""); // пишем файл aa.txt в папку d:\0 WriteToPython(cSh, "f=open(\"d:\\\\0\\\\aa.txt\",\"w+\")\n"); WriteToPython(cSh, "f.write(\"223\")\n"); WriteToPython(cSh, "f.close()\n"); WriteToPython(cSh, "exit()\n"); } else { _tprintf(_T("bRetC(install)=%d\n"),bRetC); } return 0; } Где: Скрытый текст Файл cmdShell_b.h : // --------------------------------------------------------------------------------- // file cmdShell_b.h 2020.02.06 // --------------------------------------------------------------------------------- #ifndef __cmdShell_b_H__ #define __cmdShell_b_H__ // --------------------------------------------------------------------------------- //#include "TypeDebugString.h" #include "memt.h" #include "mpipe.h" // --------------------------------------------------------------------------------- // DbgStr::TypeDebugString(_T("%s bConnected=%d"),_T(__FUNCTION__), bConnected); // DbgStr::TypeDebugString(_T("%s buf.GetDataSize()=%d"),_T(__FUNCTION__), buf.GetDataSize()); // --------------------------------------------------------------------------------- class cmdShell_b { public: static const size_t TOUT_DEF_ms = 3000; static const size_t TOUT_DEF_GET_ms = 250; static const size_t SIZE_IN = 128*1024; static const size_t SIZE_PROXY_IN = SIZE_IN; static const size_t MAX_COMMLINE_BUFF = 32768; private: protected: bool bInstalled; MEMT<char> proxyIn; MPIPE In,Out; STARTUPINFO si; PROCESS_INFORMATION pi; TCHAR commLineBuff [MAX_COMMLINE_BUFF]; DWORD dwSizeIn; DWORD dwSizeOut; size_t sizePipeInBuf; virtual bool WINAPI WaitPipeData (size_t dwToutWait=TOUT_DEF_ms,DWORD* pdwSize=NULL); virtual bool WINAPI GetPipeData (MEMT<char>& buf, DWORD dwGot=0, size_t dwToutGet=TOUT_DEF_GET_ms); virtual bool WINAPI ReadPipe (bool RetBefore, MEMT<char>& buf, DWORD dwSize); virtual bool WINAPI AddData (MEMT<char>& tar, MEMT<char>& sou); bool WINAPI CreatePipes (void); bool WINAPI PipesExist (void); bool WINAPI Wait__Process (DWORD tout); bool WINAPI Check__Pipe (DWORD *pAvail); bool WINAPI Read__Pipe (char *pData,DWORD size,DWORD *pGot); bool WINAPI Write__Pipe (char *pData,DWORD size,DWORD *pOut); public: WINAPI cmdShell_b (void); virtual WINAPI ~cmdShell_b (void); void WINAPI PreSetPipeInSize (size_t size); virtual bool WINAPI Install (const TCHAR* pCommLine); virtual bool WINAPI WriteToPipe (const void* pB, size_t size=0); virtual bool WINAPI WriteToPipe (MEMT<char>& buf); virtual bool WINAPI ReadFromPipe (MEMT<char>& buf, size_t dwToutWait=TOUT_DEF_ms, size_t dwToutGet=TOUT_DEF_GET_ms); virtual bool WINAPI WriteWaitRead ( const void* pB, size_t size, MEMT<char>& buf, size_t dwToutWait = TOUT_DEF_ms, size_t dwToutGet = TOUT_DEF_GET_ms ); bool WINAPI UnInstall (void); bool WINAPI Terminate (UINT uiCode); }; // --------------------------------------------------------------------------------- #endif Файл cmdShell_b.cpp : // --------------------------------------------------------------------------------- // FILE cmdShell_b.cpp 2020.02.05 // --------------------------------------------------------------------------------- #include "stdafx.h" #include "cmdShell_b.h" // --------------------------------------------------------------------------------- WINAPI cmdShell_b::cmdShell_b () : dwSizeIn (0), dwSizeOut (0), bInstalled (false), sizePipeInBuf (SIZE_IN) { ::ZeroMemory(&si, sizeof(si)); ::ZeroMemory(&pi, sizeof(pi)); } // --------------------------------------------------------------------------------- WINAPI cmdShell_b::~cmdShell_b () { UnInstall(); if(pi.hProcess) {::CloseHandle(pi.hProcess);} if(pi.hThread) {::CloseHandle(pi.hThread);} } // --------------------------------------------------------------------------------- void WINAPI cmdShell_b::PreSetPipeInSize (size_t size) { if(size < SIZE_IN) size = SIZE_IN; sizePipeInBuf = size; } // --------------------------------------------------------------------------------- bool WINAPI cmdShell_b::Install(const TCHAR* pCommLine) { if(!pCommLine) return false; if(bInstalled) return false; if(!proxyIn.Alloc(SIZE_PROXY_IN)) return false; dwSizeIn = (DWORD)sizePipeInBuf; if(!CreatePipes ()) return false; ::ZeroMemory(&si, sizeof(si)); si.cb = sizeof(si); ::ZeroMemory(&pi, sizeof(pi)); ::GetStartupInfo(&si); si.dwFlags = STARTF_USESTDHANDLES|STARTF_USESHOWWINDOW; si.wShowWindow = SW_HIDE; si.hStdOutput = In.GetWriteHandle(); si.hStdError = In.GetWriteHandle(); //подменяем дескрипторы для si.hStdInput = Out.GetReadHandle(); // дочернего процесса _sntprintf_s(commLineBuff,ARRAYSIZE(commLineBuff),_TRUNCATE,_T("%s"),pCommLine); // DbgStr::TypeDebugString(_T("%s %s"),_T(__FUNCTION__), commLineBuff); if ( !::CreateProcess ( NULL, commLineBuff, NULL, NULL, TRUE, CREATE_NEW_CONSOLE, NULL, NULL, &si, &pi ) ) return false; bInstalled = true; return true; } // --------------------------------------------------------------------------------- bool WINAPI cmdShell_b::WriteToPipe(const void* pB, size_t size) { if(!bInstalled) return false; if(!pB) return false; const char* pBuf = (const char*) pB; if(size==0) size=strlen(pBuf); DWORD out=0; bool RetC = false; RetC = Write__Pipe ((char*)pBuf, (DWORD)size, &out); return RetC; } // --------------------------------------------------------------------------------- bool WINAPI cmdShell_b::WriteToPipe(MEMT<char>& buf) { if(buf.GetDataSize()==0) return false; return WriteToPipe(buf.GetPointer(), buf.GetDataSize()); } // --------------------------------------------------------------------------------- bool WINAPI cmdShell_b::ReadFromPipe(MEMT<char>& buf, size_t dwToutWait, size_t dwToutGet) { if(!bInstalled) return false; bool RetC = false; DWORD dwSize = 0; buf.SetDataSize(0); for(int ii=0;ii==0;++ii,RetC=true) { if(!WaitPipeData(dwToutWait, &dwSize)) break; if(!GetPipeData(buf, dwSize, dwToutGet)) break; } return RetC; } // --------------------------------------------------------------------------------- bool WINAPI cmdShell_b::WriteWaitRead(const void* pB, size_t size, MEMT<char>& buf, size_t dwToutWait, size_t dwToutGet) { bool RetC = false; for(int ii=0;ii==0;++ii,RetC=true) { if(pB) { if(!WriteToPipe(pB, size)) break; } if(!ReadFromPipe(buf, dwToutWait, dwToutGet)) break; } return RetC; } // --------------------------------------------------------------------------------- bool WINAPI cmdShell_b::UnInstall(void) { if(!bInstalled) return false; bool RetC=false; RetC = Terminate (0); bInstalled = false; return RetC; } // --------------------------------------------------------------------------------- // --------------------------------------------------------------------------------- // bRetC = exb.ExecBatFile(_T("plink -ssh hostOrIp -P port -l user -pw password")); // --------------------------------------------------------------------------------- bool WINAPI cmdShell_b::WaitPipeData(size_t dwToutWait, DWORD* pdwSize) { bool RetC=false; DWORD dwSize=0; if(pdwSize){*pdwSize=0;} for(size_t i=0;i<dwToutWait;++i) { ::Sleep(1); if(Wait__Process(0)) break; if(Check__Pipe (&dwSize)) { if(dwSize==0) continue; else { RetC=true; if(pdwSize){*pdwSize=dwSize;} break; } } else break; } return RetC; } // --------------------------------------------------------------------------------- bool WINAPI cmdShell_b::GetPipeData(MEMT<char>& buf, DWORD dwGot_, size_t dwToutGet) { bool RetC = false; DWORD dwSize = 0; DWORD dwGot = dwGot_; if(dwGot) RetC = true; for(size_t i=0;i<dwToutGet;++i) { ::Sleep(1); if(Wait__Process(0)) break; if(Check__Pipe (&dwSize)) { if(dwSize==0) {RetC=false; break;} else { if(dwSize > dwGot) { RetC=true; dwGot=dwSize; i=0; } } } else {RetC=false;break;} } RetC = ReadPipe(RetC, buf, dwGot); return RetC; } // --------------------------------------------------------------------------------- bool WINAPI cmdShell_b::ReadPipe(bool RetBefore, MEMT<char>& buf, DWORD dwSize) { if(!RetBefore) return false; if(!buf.Alloc((size_t)dwSize*2)) return false; buf.MemSet(0); if(!buf.SetDataSize(0)) return false; DWORD dwGot=0; if(!Read__Pipe (buf.GetPointer(), (DWORD)buf.GetSize(), &dwGot)) return false; if(!buf.SetDataSize((size_t)dwGot)) return false; return true; } // --------------------------------------------------------------------------------- bool WINAPI cmdShell_b::AddData(MEMT<char>& tar, MEMT<char>& sou) { size_t sizetar = tar.GetDataSize(); size_t sizesou = sou.GetDataSize(); size_t sizeres = sizetar+sizesou; if(sizeres==0) {tar.SetDataSize(0); return true;} MEMT<char> tmp; if(!tmp.Alloc(sizeres)) return false; size_t ind = 0; for(size_t i=0;i<sizetar;++i){ tmp[ind++]=tar[i]; } for(size_t i=0;i<sizesou;++i){ tmp[ind++]=sou[i]; } tmp.SetDataSize(sizeres); tar = tmp; return true; } //---------------------------------------------------------------------------------- bool WINAPI cmdShell_b::CreatePipes (void) { if(PipesExist ()) return true; if(!In. Create(dwSizeIn)) return false; if(!Out.Create(dwSizeOut))return false; return true; } //---------------------------------------------------------------------------------- bool WINAPI cmdShell_b::PipesExist (void) { bool rIn = In.PipeExist(); bool rOut = Out.PipeExist(); return (rIn && rOut); } //---------------------------------------------------------------------------------- bool WINAPI cmdShell_b::Wait__Process (DWORD tout) { DWORD RetC = ::WaitForSingleObject(pi.hProcess, tout); if(RetC==WAIT_OBJECT_0) return true; return false; } //---------------------------------------------------------------------------------- bool WINAPI cmdShell_b::Check__Pipe (DWORD *pAvail) { return In.CheckPipe(pAvail); } //---------------------------------------------------------------------------------- bool WINAPI cmdShell_b::Read__Pipe (char *pData,DWORD size,DWORD *pGot) { return In.ReadPipe(pData,size,pGot); } //---------------------------------------------------------------------------------- bool WINAPI cmdShell_b::Write__Pipe (char *pData,DWORD size,DWORD *pOut) { return Out.WritePipe(pData,size,pOut); } //---------------------------------------------------------------------------------- bool WINAPI cmdShell_b::Terminate (UINT uiCode) { if(!bInstalled) return false; if(!pi.hProcess) return false; if(::TerminateProcess(pi.hProcess, uiCode)) return true; return false; } //---------------------------------------------------------------------------------- // DbgStr::TypeDebugString(_T("%s WaitProcess bRet=%d"),_T(__FUNCTION__),bRet); // --------------------------------------------------------------------------------- Пробовал только для x86, но сборка x64 у меня тоже есть. |
Сообщ.
#38
,
|
|
|
TerminateProcess()... абажаю. В чём проблема была послать ему "quit()"?
|
Сообщ.
#39
,
|
|
|
Цитата Qraizer @ TerminateProcess()... абажаю. |
Сообщ.
#40
,
|
|
|
Цитата Qraizer @ TerminateProcess()... абажаю. В чём проблема была послать ему "quit()"? Допустим, произошла ошибка при пользовании Питоном. Юзер забыл послать ему "exit()". Ещё интереснее получится, если вообще произойдут какие-то ошибки (в процессе отладки нашего приложения) и у нас останется висеть запущенный процесс Питона. А мы завершим работу своего приложения. И задумаем его перезапустить. А это не получится - дочерний процесс уже запущен. "Это фиаско, братан" © Или получится, но мы не сразу обнаружим вышеупомянутую ошибку и начнём плодить "потерянные" процессы массово. Terminate - это просто предохранитель. Если Питон заканчивает работу штатным образом посредством "exit()", Terminate фактически ничего и не делает. --- Terminate - не так уж редко нужно. --- На самом деле это решение можно критиковать с другой стороны. Просто для упрощения примера я использовал такую реализацию. Предположим, что Питон сам начал запускать различные приложения для своей работы. Много различных процессов. Так вот, нужно перечислить и грохнуть их все. Иначе в результате любой аварии получится неудобная проблема. Более корректный вариант у меня такой: // --------------------------------------------------------------------------------- bool WINAPI cmdShell::UnInstall(size_t dwTout) { bool RetC=false; if((bInstalled)&&(pExit)) { RetC = WriteToPipe(pExit); if(!WaitProcess((DWORD)dwTout)) { BOOL bRKPEX = KillChildProcessesEx(); if(!bRKPEX) RetC = false; } } else { if(!KillChildProcessesEx()) RetC = false; } bInstalled = false; return RetC; } // --------------------------------------------------------------------------------- |
Сообщ.
#41
,
|
|
|
Цитата ЫукпШ @ Спасибо большое, буду разбираться. я несколько подправил класс "cmdShell" |
Сообщ.
#42
,
|
|
|
ЫукпШ, ты комп тоже reset-ом ребутаешь? Ненуачё, а вдруг какая-то аппликуха откажется отвечать, какой-то драйвер не отпустит свою шелезяку...
Добавлено Любое нормально работающее нормальное приложение имеет штатный режим завершения работы. Пользователь ими вполне пользуется. Ты же наверняка не запускаешь таск-менеджер и прибиваешь аппликуху из списка процессов каждый раз? Почему тогда советуешь другим программно делать именно так? Давно Рихтера открывал? Добавлено Цитата ЫукпШ @ Никогда не нужно. Ею должен пользоваться только пользователь только из таск-менеджера. Terminate - не так уж редко нужно. |
Сообщ.
#43
,
|
|
|
Цитата Qraizer @ ЫукпШ, ты комп тоже reset-ом ребутаешь? Ненуачё, а вдруг какая-то аппликуха откажется отвечать, какой-то драйвер не отпустит свою шелезяку... Qraizer, ниочём. ----- А вообще у меня есть такая функция - в софте у микроконтроллеров - аппаратный reset. Можно даже дать по сети. "И чо ?". Никаких комплексов - если надо, значит сделаем. ----- Есть даже такой характерный приём программирования системы. Хорошо известный в узких кругах. Аппаратный сброс на микроконтроллер подаётся от генератора постоянно. Во временном промежутками между сбросами контроллер и выполняет всю работу. Такая вычислительная система не может зависнуть... ----- Ты преподавателем работаешь ? Добавлено Цитата Qraizer @ Любое нормально работающее нормальное приложение имеет штатный режим завершения работы. А я тебе и ответил - что в штатном режиме Terminate и не используется. Это предохранитель на не предвиденную ситуацию и не штатный режим. Который всегда может возникнуть в любой момент. В том числе и по прямой ошибке программиста. |
Сообщ.
#44
,
|
|
|
Цитата ЫукпШ @ Это пять.Аппаратный сброс на микроконтроллер подаётся от генератора постоянно. Во временном промежутками между сбросами контроллер и выполняет всю работу. Такая вычислительная система не может зависнуть... Вэлкам ту Холиварс, ЫукпШ. Создавай тему, тут заканчиваем, бо B.V. счас взбесится. Перед созданием рекомендую ознакомиться с такими типами систем, как hosted и freestanding, пригодится. |
Сообщ.
#45
,
|
|
|
Цитата Qraizer @ Цитата ЫукпШ @ Вчера, 23:56 Terminate - не так уж редко нужно. Никогда не нужно. Ею должен пользоваться только пользователь только из таск-менеджера. Бывает, нужно: сам применяю, когда идёт очередь выполнения задач, и задержка цикла гораздо критичнее принудительного завершения процесса. Приходится прибивать. |