Non solo può essere fatto, può essere fatto con nient'altro che un file batch! :-)
Il problema può essere risolto utilizzando un file temporaneo come "pipe". La comunicazione bidirezionale richiede due file "pipe".
Il processo A legge stdin da "pipe1" e scrive stdout su "pipe2" Il
processo B legge stdin da "pipe2" e scrive stdout su "pipe1"
È importante che entrambi i file esistano prima dell'avvio di entrambi i processi. I file dovrebbero essere vuoti all'inizio.
Se un file batch tenta di leggere da un file che si trova alla fine corrente, non restituisce semplicemente nulla e il file rimane aperto. Quindi la mia routine readLine legge continuamente fino a quando non ottiene un valore non vuoto.
Voglio essere in grado di leggere e scrivere una stringa vuota, quindi la mia routine writeLine aggiunge un carattere in più che readLine rimuove.
Il mio processo A controlla il flusso. Inizia le cose scrivendo 1 (messaggio a B), quindi entra in un ciclo con 10 iterazioni in cui legge un valore (messaggio da B), aggiunge 1 e quindi scrive il risultato (messaggio a B). Alla fine attende l'ultimo messaggio da B, quindi scrive un messaggio "Esci" su B ed esce.
Il mio processo B è in un ciclo condizionatamente infinito che legge un valore (messaggio da A), aggiunge 10 e quindi scrive il risultato (messaggio su A). Se B legge mai un messaggio "Esci", termina immediatamente.
Volevo dimostrare che la comunicazione è completamente sincrona, quindi introduco un ritardo nei cicli di processo A e B.
Si noti che la procedura readLine è in un ciclo stretto che abusa continuamente sia della CPU che del file system mentre attende l'input. È possibile aggiungere un ritardo PING al loop, ma i processi non saranno così reattivi.
Uso una vera pipa per comodità sia per avviare i processi A che B. Ma la pipe non è funzionale in quanto nessuna comunicazione vi passa attraverso. Tutte le comunicazioni avvengono tramite i miei file temporanei "pipe".
Avrei potuto anche usare START / B per avviare i processi, ma poi devo rilevare quando entrambi terminano in modo da sapere quando eliminare i file temporanei "pipe". È molto più semplice usare la pipa.
Ho scelto di mettere tutto il codice in un singolo file: lo script principale che avvia A e B, così come il codice per A e B. Avrei potuto usare un file di script separato per ogni processo.
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
--PRODUZIONE--
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
La vita è un po 'più semplice con un linguaggio di livello superiore. Di seguito è riportato un esempio che utilizza VBScript per i processi A e B. Uso ancora batch per avviare i processi. Uso un metodo molto interessante descritto in È possibile incorporare ed eseguire VBScript in un file batch senza utilizzare un file temporaneo? per incorporare più script VBS in un singolo script batch.
Con un linguaggio superiore come VBS, possiamo usare una normale pipe per passare informazioni da A a B. Abbiamo solo bisogno di un singolo file "pipe" temporaneo per passare informazioni da B a A. Perché ora abbiamo una pipe funzionante, la A Non è necessario che il processo invii un messaggio "esci" a B. Il processo B esegue semplicemente un ciclo fino a quando non raggiunge la fine del file.
È bello avere accesso a una corretta funzione sleep in VBS. Ciò mi consente di introdurre facilmente un breve ritardo nella funzione readLine per interrompere la CPU.
Tuttavia, c'è una ruga in readLIne. All'inizio stavo ricevendo errori intermittenti fino a quando mi sono reso conto che a volte readLine avrebbe rilevato informazioni disponibili su stdin e avrebbe immediatamente provato a leggere la riga prima che B avesse la possibilità di terminare di scrivere la riga. Ho risolto il problema introducendo un breve ritardo tra il test di fine file e la lettura. Un ritardo di 5 msec sembrava fare il trucco per me, ma l'ho raddoppiato a 10 msec solo per essere al sicuro. È molto interessante che il batch non soffra di questo problema. Ne abbiamo discusso brevemente (5 brevi post) su 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>
L'output è lo stesso della soluzione batch pura, tranne che le righe finali "quit" non sono presenti.