दो प्रोग्राम जिनके StdIn और StdOut बंधे हुए हैं


12

मान लीजिए कि मेरे पास दो कार्यक्रम हैं ProgramAऔर कहा जाता है ProgramB। मैं विंडोज सीएमडी दुभाषिया में उन दोनों को एक साथ चलाना चाहता हूं। लेकिन मैं चाहता हूँ StdOutकी ProgramAके शौकीन StdInकी ProgramBऔर StdOutसे ProgramBके शौकीन StdInकी ProgramA

कुछ इस तरह

 ________________ ________________
| | | |
| StdIn (== ← === In == (StdOut) |
| कार्यक्रम ए | | कार्यक्रम बी |
| | | |
| StdOut) == → === → ==) StdIn |
| ________________ | | ________________ |

क्या ऐसा करने के लिए कोई कमांड है - cmd से इस कार्यक्षमता को प्राप्त करने का कोई तरीका?


4
यूनिक्स पर मैं नामित पाइपों का उपयोग करूँगा, ऐसा करने के लिए, खिड़कियों में कुछ नाम के पाइप हैं जो पूरी तरह से अलग हैं और संभवतः लागू नहीं होते हैं।
जस

@Jasen यहाँ एक टिप्पणी के अनुसार linuxjournal.com/article/2156 नाम के पाइप साइबरविन पर काम कर सकते हैं .. यदि ऐसा है तो शायद आप एक जवाब के रूप में विस्तृत और पोस्ट कर सकते हैं, हालांकि पहले
साइबरजी

मुझे लगता है कि कार्यक्रमों को भी लिखा जाना चाहिए ताकि लूप न हो .. इसलिए यदि स्टडआउट एक खाली लाइन है तो स्टड को न खिलाएं, और अगर स्टड को कुछ भी नहीं है तो बाहर निकलें। इस प्रकार एक अनंत लूप से बचना? लेकिन ब्याज से बाहर, आवेदन क्या है?
बार्लॉप

2
क्या आप "एलिज़ा" के दो उदाहरण चाहते हैं एक बातचीत है?
जस

यदि प्रोग्राम को सावधानीपूर्वक डिज़ाइन नहीं किया गया है तो वे इसे गतिरोध में ले जा सकते हैं - दोनों दूसरे से इनपुट की प्रतीक्षा कर रहे हैं और कभी कुछ नहीं होता है (या दोनों पूर्ण बफ़र्स को लिखने की कोशिश कर रहे हैं और कभी भी उन्हें खाली करने के लिए कुछ भी नहीं पढ़ते हैं )
रैंडम --३२

जवाबों:


5

न केवल यह किया जा सकता है, यह एक बैच फ़ाइल के अलावा कुछ भी नहीं किया जा सकता है! :-)

"पाइप" के रूप में एक अस्थायी फ़ाइल का उपयोग करके समस्या को हल किया जा सकता है। द्विदिश संचार को दो "पाइप" फाइलों की आवश्यकता होती है।

प्रोसेस A स्टड को "पाइप 1" से पढ़ता है और "पाइप 2" को stdout लिखता है।
प्रोसेस बी "पाइप 2" से स्टड को पढ़ता है और "पाइप 1" को स्टडआउट लिखता है

यह महत्वपूर्ण है कि दोनों फाइलें या तो प्रक्रिया शुरू करने से पहले मौजूद हों। फाइलें शुरू में खाली होनी चाहिए।

यदि बैच फ़ाइल वर्तमान छोर पर होने वाली फ़ाइल से पढ़ने का प्रयास करती है, तो यह बस कुछ भी नहीं लौटाती है, और फ़ाइल खुली रहती है। इसलिए मेरी रीडलाइन नियमित रूप से लगातार पढ़ती है जब तक कि यह एक गैर-रिक्त मान न हो जाए।

मैं एक खाली स्ट्रिंग को पढ़ने और लिखने में सक्षम होना चाहता हूं, इसलिए मेरी राइटलाइन रूटीन में एक अतिरिक्त चरित्र है जो कि रीडलाइन स्ट्रिप्स को बंद कर देता है।

मेरी A प्रक्रिया प्रवाह को नियंत्रित करती है। यह 1 (बी को संदेश) लिखकर चीजें शुरू करता है, और फिर 10 पुनरावृत्तियों के साथ एक लूप में प्रवेश करता है जहां यह एक मूल्य (बी से संदेश) पढ़ता है, 1 जोड़ता है, और फिर परिणाम (बी को संदेश) लिखता है। अंत में यह B के अंतिम संदेश की प्रतीक्षा करता है, और फिर B को एक "छोड़" संदेश लिखता है और बाहर निकलता है।

मेरी बी प्रक्रिया एक सशर्त अंतहीन लूप में है जो एक मान (ए से संदेश) पढ़ता है, 10 जोड़ता है, और फिर परिणाम (ए को संदेश) लिखता है। यदि बी कभी "छोड़" संदेश पढ़ता है, तो यह तुरंत समाप्त हो जाता है।

मैं प्रदर्शित करना चाहता था कि संचार पूरी तरह से समकालिक है, इसलिए मैं ए और बी दोनों प्रक्रिया लूप में देरी का परिचय देता हूं।

ध्यान दें कि readLine प्रक्रिया एक तंग लूप में है जो इनपुट के लिए प्रतीक्षा करते समय सीपीयू और फाइल सिस्टम दोनों को लगातार गाली देती है। एक पिंग देरी को लूप में जोड़ा जा सकता है, लेकिन फिर प्रक्रियाएं उतने उत्तरदायी नहीं होंगी।

मैं ए और बी दोनों प्रक्रियाओं को लॉन्च करने के लिए एक सुविधा के रूप में एक सच्चे पाइप का उपयोग करता हूं। लेकिन पाइप गैर-कार्यात्मक है कि कोई संचार इसके माध्यम से नहीं गुजरता है। सभी संचार मेरी अस्थायी "पाइप" फाइलों के माध्यम से है।

मैं प्रक्रियाओं को लॉन्च करने के लिए बस START / B का उपयोग कर सकता था, लेकिन फिर मुझे यह पता लगाना होगा कि वे दोनों कब समाप्त होंगे ताकि मुझे पता चले कि अस्थायी "पाइप" फ़ाइलों को कब हटाया जाए। पाइप का उपयोग करना बहुत सरल है।

मैंने सभी कोड एक ही फाइल में डालने का फैसला किया - ए और बी लॉन्च करने वाली मास्टर स्क्रिप्ट, साथ ही ए और बी के लिए कोड। मैं प्रत्येक प्रक्रिया के लिए एक अलग स्क्रिप्ट फ़ाइल का उपयोग कर सकता था।

test.bat

@echo off

if "%~1" equ "" (

    copy nul pipe1.txt >nul
    copy nul pipe2.txt >nul

    "%~f0" A <pipe1.txt >>pipe2.txt | "%~f0" B <pipe2.txt >>pipe1.txt

    del pipe1.txt pipe2.txt

    exit /b

)


setlocal enableDelayedExpansion
set "prog=%~1"
goto !prog!


:A
call :writeLine 1
for /l %%N in (1 1 5) do (
  call :readLine
    set /a ln+=1
  call :delay 1
    call :writeLine !ln!
)
call :readLine
call :delay 1
call :writeLine quit
exit /b


:B
call :readLine
if !ln! equ quit exit /b
call :delay 1
set /a ln+=10
call :writeLine !ln!
goto :B


:readLine
set "ln="
set /p "ln="
if not defined ln goto :readLine
set "ln=!ln:~0,-1!"
>&2 echo !prog!  reads !ln!
exit /b


:writeLine
>&2 echo !prog! writes %*
echo(%*.
exit /b


:delay
setlocal
set /a cnt=%1+1
ping localhost /n %cnt% >nul
exit /b

--OUTPUT--

C:\test>test
A writes 1
B  reads 1
B writes 11
A  reads 11
A writes 12
B  reads 12
B writes 22
A  reads 22
A writes 23
B  reads 23
B writes 33
A  reads 33
A writes 34
B  reads 34
B writes 44
A  reads 44
A writes 45
B  reads 45
B writes 55
A  reads 55
A writes 56
B  reads 56
B writes 66
A  reads 66
A writes quit
B  reads quit

उच्च स्तर की भाषा के साथ जीवन थोड़ा आसान है। नीचे एक उदाहरण है जो A और B प्रक्रियाओं के लिए VBScript का उपयोग करता है। मैं अभी भी प्रक्रियाओं को लॉन्च करने के लिए बैच का उपयोग करता हूं। मैं एक बहुत ही शांत विधि का उपयोग करता हूं जो एक अस्थायी फ़ाइल का उपयोग किए बिना एक बैच फ़ाइल के भीतर VBScript को एम्बेड और निष्पादित करना संभव है? एक ही बैच स्क्रिप्ट के भीतर कई VBS स्क्रिप्ट एम्बेड करने के लिए।

वीबीएस जैसी उच्च भाषा के साथ, हम ए से बी तक जानकारी पास करने के लिए एक सामान्य पाइप का उपयोग कर सकते हैं। हमें बी से ए तक जानकारी पास करने के लिए केवल एक अस्थायी "पाइप" फ़ाइल की आवश्यकता है क्योंकि हमारे पास अब एक कार्यशील पाइप है, ए। प्रक्रिया को बी के लिए एक "छोड़ दिया" संदेश भेजने की आवश्यकता नहीं है। बी प्रक्रिया बस छोरों तक जाती है जब तक कि यह फ़ाइल के अंत तक नहीं पहुंचती।

यह निश्चित है कि वीबीएस में एक उचित नींद समारोह के लिए उपयोग करना अच्छा है। यह मुझे सीपीयू को ब्रेक देने के लिए रीडलाइन फ़ंक्शन में आसानी से एक छोटी देरी शुरू करने में सक्षम बनाता है।

हालाँकि, readLIne के भीतर एक शिकन है। पहले तो मुझे रुक-रुक कर असफलताएँ मिल रही थीं, जब तक मुझे एहसास नहीं हो गया था कि कभी-कभी रीडलाइन पता लगा लेगी कि जानकारी स्टड पर उपलब्ध है, और तुरंत बी को लाइन लिखने का मौका देने से पहले लाइन को पढ़ने की कोशिश करेंगे। मैंने एंड-ऑफ़-फ़ाइल परीक्षण और रीड के बीच एक छोटी देरी की शुरुआत करके समस्या को हल किया। 5 मिसे की देरी से मेरे लिए चाल चल रही थी, लेकिन मुझे दोगुना हो गया कि 10 मिसेक सिर्फ सुरक्षित पक्ष में होना चाहिए। यह बहुत दिलचस्प है कि बैच को इस मुद्दे का सामना नहीं करना पड़ता है। हमने इस बारे में http://www.dostips.com/forum/viewtopic.php?f=3&t=7078#p47432 पर संक्षिप्त (5 संक्षिप्त पोस्ट) चर्चा की ।

<!-- : Begin batch script
@echo off
copy nul pipe.txt >nul
cscript //nologo "%~f0?.wsf" //job:A <pipe.txt | cscript //nologo "%~f0?.wsf" //job:B >>pipe.txt
del pipe.txt
exit /b


----- Begin wsf script --->
<package>

<job id="A"><script language="VBS">

  dim ln, n, i
  writeLine 1
  for i=1 to 5
    ln = readLine
    WScript.Sleep 1000
    writeLine CInt(ln)+1
  next
  ln = readLine

  function readLine
    do
      if not WScript.stdin.AtEndOfStream then
        WScript.Sleep 10 ' Pause a bit to let B finish writing the line
        readLine = WScript.stdin.ReadLine
        WScript.stderr.WriteLine "A  reads " & readLine
        exit function
      end if
      WScript.Sleep 10 ' This pause is to give the CPU a break
    loop
  end function

  sub writeLine( msg )
    WScript.stderr.WriteLine "A writes " & msg
    WScript.stdout.WriteLine msg
  end sub

</script></job>

<job id="B"> <script language="VBS">

  dim ln, n
  do while not WScript.stdin.AtEndOfStream
    ln = WScript.stdin.ReadLine
    WScript.stderr.WriteLine "B  reads " & ln
    n = CInt(ln)+10
    WScript.Sleep 1000
    WScript.stderr.WriteLine "B writes " & n
    WScript.stdout.WriteLine n
  loop

</script></job>

</package>

आउटपुट शुद्ध बैच समाधान के साथ ही है, अंतिम "छोड़" लाइनों के अलावा नहीं हैं।


4

नोट- पूर्वव्यापी में, प्रश्न को फिर से पढ़ना, यह वह नहीं है जो पूछा जाता है। चूंकि, यह दो प्रक्रियाओं को एक साथ जोड़ता है, (एक दिलचस्प तरीके से जो एक नेटवर्क पर भी काम करेगा!), यह दोनों तरीकों को जोड़ता नहीं है।


मुझे आशा है कि आपको इसके कुछ उत्तर मिलेंगे।

यहाँ मेरा उत्तर है, लेकिन इसे स्वीकार नहीं करते, अन्य उत्तरों की प्रतीक्षा करें, मैं कुछ अन्य उत्तरों को देखने के लिए उत्सुक हूं।

यह साइबरविन से किया गया था। और 'एनसी' कमांड (चतुर एक) का उपयोग करना। 'Wc -l' सिर्फ रेखाओं को गिनता है। तो मैं इस मामले में, जो कुछ भी दो कमांड को लिंक कर रहा हूं, इको और डब्ल्यूसी, एनसी का उपयोग कर रहा है।

बाईं ओर कमान पहले किया गया था।

nc एक कमांड है जो सर्वर के लिए) a) सर्वर बनाने में सक्षम है, या b) टेलनेट कमांड को कच्चे मोड में कनेक्ट करता है। मैं बाएं कमांड में 'ए' उपयोग कर रहा हूं, और राइट कमांड में 'बी' उपयोग।

तो nc एक इनपुट के इन्तजार में यह सुनकर बैठ गया, और फिर उस इनपुट को पाइप करेगा wc -lऔर लाइनों की गणना करेगा और इनपुट की गई लाइनों की संख्या को आउटपुट करेगा।

मैंने तब कुछ पाठ को प्रतिध्वनित करने के लिए लाइन चलाई और उस कच्चे को 127.0.0.1:123 पर भेजा जो कि उल्लेखित सर्वर है।

यहाँ छवि विवरण दर्ज करें

आप nc.exe आदेश को cygwin से कॉपी कर सकते हैं और उसी निर्देशिका में उस cygwin1.dll फ़ाइल का उपयोग करके प्रयास कर सकते हैं। या आप इसे मेरे जैसे ही साइबरविन से कर सकते हैं। मुझे gnwin32 में nc.exe नहीं दिख रहा है। उनकी एक खोज है http://gnuwin32.sourceforge.net/ और nc या netcat नहीं। लेकिन आप cygwin https://cygwin.com/install.html प्राप्त कर सकते हैं


इससे पहले कि मैं समझ रहा था कि यह क्या हो रहा था के माध्यम से इसे पढ़ने के लिए मुझे दस बार पसंद आया ..... जो कि बहुत ही चालाक है
डार्थरुबिक

@DarthRubik हाँ, और आप यह netstat -aon | find ":123"देखने के लिए उपयोग कर सकते हैं कि बाईं ओर के कमांड ने सर्वर बनाया
बार्लॉप

लेकिन आप दूसरी दिशा (यानी wcपीछे से echoकमांड के लिए) कैसे संवाद करते हैं ।
डार्थरुबिक

जब मैं इसे दोनों तरीकों से करने की कोशिश करता हूं, तो शायद यह किसी तरह के पाश में चला जाए।
बार्लोप

nc -lp9999 | prog1 | prog2 | nc 127.0.0.1 9999यह सुनिश्चित करने के लिए कदम उठाए जा सकते हैं कि बफ़र्स को समयबद्ध तरीके से
प्रवाहित किया जाए

2

एक हैक (मैं ऐसा नहीं करना पसंद करूंगा, लेकिन यह वह है जो मैं अभी के लिए जा रहा हूं) आपके लिए ऐसा करने के लिए एक C # एप्लिकेशन लिखना है । मैंने इस कार्यक्रम में कुछ प्रमुख विशेषताओं को लागू नहीं किया है (जैसे वास्तव में मुझे दिए गए तर्कों का उपयोग करके), लेकिन यहाँ यह है:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;


namespace Joiner
{
    class Program
    {
        static Process A;
        static Process B;
        static void AOutputted(object s, DataReceivedEventArgs a)
        {
            Console.WriteLine("A:" + a.Data);
            //Console.WriteLine("Sending to B");
            B.StandardInput.WriteLine(a.Data);
        }
        static void BOutputted(object s, DataReceivedEventArgs a)
        {
            Console.WriteLine("B:" + a.Data);
            //Console.WriteLine("Sending to A");
            A.StandardInput.WriteLine(a.Data);
        }
        static void Main(string[] args)
        {

            A = new Process();
            B = new Process();
            A.StartInfo.FileName = "help";
            B.StartInfo.FileName = "C:\\Users\\Owner\\Documents\\Visual Studio 2010\\Projects\\Joiner\\Test\\bin\\Debug\\Test.exe";

            A.StartInfo.Arguments = "mkdir";
            //B.StartInfo.Arguments = "/E /K type CON";

            A.StartInfo.UseShellExecute = false;
            B.StartInfo.UseShellExecute = false;

            A.StartInfo.RedirectStandardOutput = true;
            B.StartInfo.RedirectStandardOutput = true;

            A.StartInfo.RedirectStandardInput = true;
            B.StartInfo.RedirectStandardInput = true;

            A.OutputDataReceived += AOutputted;
            B.OutputDataReceived += BOutputted;

            A.Start();
            B.Start();

            A.BeginOutputReadLine();
            B.BeginOutputReadLine();



            while (!A.HasExited || !B.HasExited) { }
            Console.ReadLine();

        }
    }
}

फिर अंततः, जब यह कार्यक्रम पूरी तरह कार्यात्मक है और डिबग कोड हटा दिया गया है, तो आप इसे इस तरह से उपयोग करेंगे:

joiner "A A's args" "B B's Args"
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.