Dies ist nicht nur möglich, sondern auch nur mit einer Batch-Datei! :-)
Das Problem kann gelöst werden, indem eine temporäre Datei als "Pipe" verwendet wird. Für die bidirektionale Kommunikation sind zwei "Pipe" -Dateien erforderlich.
Prozess A liest stdin von "pipe1" und schreibt stdout in "pipe2".
Prozess B liest stdin von "pipe2" und schreibt stdout in "pipe1".
Es ist wichtig, dass beide Dateien vorhanden sind, bevor Sie einen der beiden Prozesse starten. Die Dateien sollten zu Beginn leer sein.
Wenn eine Batchdatei versucht, aus einer Datei zu lesen, die sich gerade am aktuellen Ende befindet, wird einfach nichts zurückgegeben, 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, daher hängt meine writeLine-Routine ein zusätzliches Zeichen an, das die readLine entfernt.
Mein A-Prozess steuert den Fluss. Es initiiert Dinge durch Schreiben von 1 (Nachricht an B) und tritt dann in eine Schleife mit 10 Iterationen ein, in der es einen Wert liest (Nachricht von B), 1 addiert und dann das Ergebnis schreibt (Nachricht an B). Schließlich wartet es auf die letzte Nachricht von B und schreibt dann eine "Beenden" -Nachricht an B und wird beendet.
Mein B-Prozess befindet sich in einer bedingten Endlosschleife, die einen Wert liest (Nachricht von A), 10 addiert und dann das Ergebnis schreibt (Nachricht an A). Wenn B jemals eine "Beenden" -Nachricht liest, wird sie sofort beendet.
Ich wollte zeigen, dass die Kommunikation vollständig synchron ist, daher füge ich eine Verzögerung sowohl in der A- als auch in der B-Prozessschleife ein.
Beachten Sie, dass sich die readLine-Prozedur in einer engen Schleife befindet, die sowohl die CPU als auch das Dateisystem kontinuierlich missbraucht, während sie auf die Eingabe wartet. Der Schleife könnte eine PING-Verzögerung hinzugefügt werden, aber dann reagieren die Prozesse nicht so schnell.
Ich verwende 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 geleitet wird. Die gesamte Kommunikation erfolgt über meine temporären "Pipe" -Dateien.
Ich hätte genauso gut START / B verwenden können, um die Prozesse zu starten, aber dann muss ich erkennen, wann beide beendet werden, damit ich weiß, wann die temporären "Pipe" -Dateien gelöscht werden müssen. Es ist viel einfacher, das Rohr zu benutzen.
Ich habe mich dafür entschieden, den gesamten Code in eine einzige Datei zu packen - das Masterskript, mit dem A und B gestartet werden, sowie den Code für A und B. Ich hätte für jeden Prozess eine separate Skriptdatei 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
Mit einer höheren Sprache ist das Leben ein bisschen einfacher. Unten finden Sie ein Beispiel, das VBScript für die Prozesse A und B verwendet. Ich benutze immer noch Batch, um die Prozesse zu starten. Ich verwende eine sehr coole Methode, die unter Ist es möglich, VBScript in eine Batchdatei einzubetten und auszuführen, ohne eine temporäre Datei zu verwenden? um mehrere VBS-Skripte in ein einziges Batch-Skript einzubetten.
Mit einer höheren Sprache wie VBS können wir eine normale Pipe verwenden, um Informationen von A nach B zu übergeben. Wir benötigen nur eine einzige temporäre "Pipe" -Datei, um Informationen von B zurück nach A zu übergeben. Da wir jetzt eine funktionierende Pipe haben, die A. Der Prozess muss keine "Beenden" -Nachricht an B senden. Der B-Prozess wird einfach wiederholt, bis das Dateiende erreicht ist.
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ühren, um der CPU eine Pause zu geben.
Es gibt jedoch eine Falte in readLIne. Zuerst bekam ich zeitweise Fehler, bis mir klar wurde, dass readLine manchmal feststellte, dass Informationen auf stdin verfügbar sind, und sofort versuchte, die Zeile zu lesen, bevor B die Möglichkeit hatte, das Schreiben der Zeile abzuschließen. Ich habe das Problem gelöst, indem ich eine kurze Verzögerung zwischen dem Dateiende-Test und dem Lesen eingeführt habe. Eine Verzögerung von 5 ms schien den Trick für mich zu tun, aber ich habe das auf 10 ms verdoppelt, nur um auf der sicheren Seite zu sein. Es ist sehr interessant, dass bei Batch dieses Problem nicht auftritt. 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 die gleiche wie bei der reinen Batch-Lösung, außer dass die letzten "Quit" -Zeilen nicht vorhanden sind.