Es kann nicht nur gemacht werden, es kann nur eine Batch-Datei verwendet werden! :-)
Das Problem kann gelöst werden, indem eine temporäre Datei als "Pipe" verwendet wird. Die bidirektionale Kommunikation erfordert zwei "Pipe" -Dateien.
Prozess A liest stdin aus "pipe1" und schreibt stdout in "pipe2".
Prozess B liest stdin aus "pipe2" und schreibt stdout in "pipe1".
Es ist wichtig, dass beide Dateien vorhanden sind, bevor einer der beiden Prozesse gestartet wird. Die Dateien sollten zu Beginn leer sein.
Wenn eine Stapeldatei versucht, aus einer Datei zu lesen, die sich gerade am aktuellen Ende befindet, gibt sie einfach nichts zurück und die Datei bleibt geöffnet. Meine readLine-Routine liest also kontinuierlich, bis sie einen nicht leeren Wert erhält.
Ich möchte in der Lage sein, eine leere Zeichenfolge zu lesen und zu schreiben, sodass meine writeLine-Routine ein zusätzliches Zeichen anfügt, das von der readLine entfernt wird.
Mein A-Prozess steuert den Fluss. Es initiiert Dinge durch Schreiben von 1 (Nachricht an B) und führt dann eine Schleife mit 10 Iterationen durch, in der ein Wert (Nachricht von B) gelesen wird, 1 hinzugefügt wird und das Ergebnis (Nachricht an B) geschrieben wird. Schließlich wartet er auf die letzte Nachricht von B, schreibt dann eine "Quit" -Nachricht an B und beendet den Vorgang.
Mein B-Prozess befindet sich in einer bedingt endlosen Schleife, die einen Wert (Nachricht von A) liest, 10 addiert und dann das Ergebnis (Nachricht an A) schreibt. Wenn B jemals eine "Quit" -Meldung liest, wird sie sofort abgebrochen.
Ich wollte zeigen, dass die Kommunikation vollständig synchron ist. Daher führe ich eine Verzögerung in den Prozessschleifen A und B ein.
Beachten Sie, dass sich die readLine-Prozedur in einer engen Schleife befindet, die sowohl die CPU als auch das Dateisystem ständig missbraucht, während sie auf Eingaben wartet. Eine PING-Verzögerung könnte der Schleife hinzugefügt werden, aber dann reagieren die Prozesse nicht so schnell.
Ich benutze eine echte Pipe, um sowohl den A- als auch den B-Prozess zu starten. Die Pipe ist jedoch nicht funktionsfähig, da keine Kommunikation durch sie hindurchgeht. Die gesamte Kommunikation erfolgt über meine temporären "Pipe" -Dateien.
Ich hätte START / B genauso gut zum Starten der Prozesse verwenden können, aber dann muss ich erkennen, wann beide beendet werden, damit ich weiß, wann die temporären "Pipe" -Dateien gelöscht werden. Es ist viel einfacher, das Rohr zu verwenden.
Ich habe mich entschieden, den gesamten Code in eine einzige Datei zu packen - das Master-Skript, das A und B startet, sowie den Code für A und B. Ich hätte für jeden Prozess eine eigene Skript-Datei verwenden können.
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
--AUSGABE--
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
Das Leben ist mit einer höheren Niveausprache etwas einfacher. Im Folgenden finden Sie ein Beispiel, in dem VBScript für die A- und B-Prozesse verwendet wird. Ich benutze immer noch Batch, um die Prozesse zu starten. Ich verwende eine sehr coole Methode. Kann VBScript in eine Batchdatei eingebettet und ausgeführt werden, ohne eine temporäre Datei zu verwenden? Einbetten mehrerer VBS-Skripts in ein einzelnes Batch-Skript.
Mit einer höheren Sprache wie VBS können wir eine normale Pipe verwenden, um Informationen von A an B zu übergeben. Wir benötigen nur eine einzige temporäre "Pipe" -Datei, um Informationen von B zurück an A zu übergeben. Weil wir jetzt eine funktionierende Pipe haben, das A Der Prozess muss keine "Quit" -Nachricht an B senden. Der B-Prozess durchläuft einfach eine Schleife, bis er das Dateiende erreicht.
Es ist sicher schön, Zugang zu einer richtigen Schlaffunktion in VBS zu haben. Dadurch kann ich leicht eine kurze Verzögerung in die readLine-Funktion einfügen, um die CPU zu unterbrechen.
Allerdings gibt es innerhalb von readLIne eine Falte. Zuerst bekam ich intermittierende Fehler, bis mir klar wurde, dass readLine manchmal Informationen über stdin zur Verfügung stellte und sofort versuchte, die Zeile zu lesen, bevor B die Möglichkeit hatte, die Zeile fertig zu schreiben. Ich löste das Problem, indem ich eine kurze Verzögerung zwischen dem Dateiende-Test und dem Lesen einführte. Eine Verzögerung von 5 ms schien den Trick für mich zu erfüllen, aber ich verdoppelte diese auf 10 ms, um auf der sicheren Seite zu sein. Es ist sehr interessant, dass Batch dieses Problem nicht erleidet. Wir haben dies kurz besprochen (5 kurze Beiträge) unter http://www.dostips.com/forum/viewtopic.php?f=3&t=7078#p47432 .
<!-- : 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>
Die Ausgabe ist dieselbe wie bei der reinen Batch-Lösung, außer dass die abschließenden "Quit" -Linien nicht vorhanden sind.