Not only can it be done, it can be done with nothing but a batch file! :-)
The problem can be solved by using a temporary file as a "pipe". Bidirectional communication requires two "pipe" files.
Process A reads stdin from "pipe1" and writes stdout to "pipe2"
Process B reads stdin from "pipe2" and writes stdout to "pipe1"
It is important that both files exist prior to launching either process. The files should be empty at the start.
If a batch file attempts to read from a file that happens to be at the current end, it simply returns nothing, and the file remains open. So my readLine routine continuously reads until it gets a non-empty value.
I want to be able to read and write an empty string, so my writeLine routine appends an extra character which the readLine strips off.
My A process controls the flow. It initiates things by writing 1 (message to B), and then enters a loop with 10 iterations where it reads a value (message from B), adds 1, and then writes the result (message to B). Finally it waits for the last message from B, and then writes a "quit" message to B and exits.
My B process is in a conditionally endless loop that reads a value (message from A), adds 10, and then writes the result (message to A). If B ever reads a "quit" message, then it terminates immediately.
I wanted to demonstrate that the communication is fully synchronous, so I introduce a delay in both the A and B process loops.
Note that the readLine procedure is in a tight loop that continuously abuses both the CPU and the file system while it waits for input. A PING delay could be added to the loop, but then the processes will not be as responsive.
I use a true pipe as a convenience to launch both the A and B processes. But the pipe is non-functional in that no communication passes through it. All communication is via my temporary "pipe" files.
I could just as well have used START /B to launch the processes, but then I have to detect when they both terminate so that I know when to delete the temporary "pipe" files. It is much simpler to use the pipe.
I chose to put all code in a single file - the master script that launches A and B, as well as the code for A and B. I could have used a separate script file for each process.
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
Life is a little bit easier with a higher level language. Below is an example that uses VBScript for the A and B processes. I still use batch to launch the processes. I use a very cool method described at Is it possible to embed and execute VBScript within a batch file without using a temporary file? to embed multiple VBS scripts within a single batch script.
With a higher language like VBS, we can use a normal pipe to pass info from A to B. We only need a single temporary "pipe" file to pass info from B back to A. Because we now have a functioning pipe, the A process does not need to send a "quit" message to B. The B process simply loops until it reaches end-of-file.
It sure is nice having access to a proper sleep function in VBS. This enables me to easily introduce a short delay in the readLine function to give the CPU a break.
However, there is one wrinkle within readLIne. At first I was getting intermittent failures until I realized that sometimes readLine would detect information is available on stdin, and would immediately try to read the line before B had a chance to finish writing the line. I solved the problem by introducing a short delay between the end-of-file test and the read. A delay of 5 msec seemed to do the trick for me, but I doubled that to 10 msec just to be on the safe side. It is very interesting that batch does not suffer this issue. We discussed this briefly (5 short posts) at 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>
Output is the same as with the pure batch solution, except the final "quit" lines are not there.