Sadece bir toplu iş dosyası dışında hiçbir şey ile yapılabilir! :-)
Sorun geçici bir dosya "yöneltme" olarak kullanılarak çözülebilir. Çift yönlü iletişim için iki "kanal" dosyası gerekir.
İşlem A stdin'i "pipe1"
den okur ve stdout'u "pipe2" ye yazar. İşlem B stdin'i "pipe2" den okur ve stdout'u "pipe1" e yazar.
Her iki dosyanın da her iki işlemi başlatmadan önce bulunması önemlidir. Dosyalar başlangıçta boş olmalıdır.
Toplu iş dosyası geçerli uçta olan bir dosyadan okumaya çalışırsa, hiçbir şey döndürmez ve dosya açık kalır. Bu nedenle, readLine yordamım, boş olmayan bir değer alana kadar sürekli olarak okur.
Boş bir dize okumak ve yazmak istiyorum, bu yüzden benim writeLine rutin readLine şeritler ek bir karakter ekler.
A sürecim akışı kontrol eder. 1 (B'ye mesaj) yazarak işleri başlatır ve 10 değerini yineleyen bir döngüye girer (burada bir değer okur (B'den mesaj), 1 ekler ve sonra sonucu yazar (B'ye mesaj). Son olarak B'den son mesajı bekler ve sonra B'ye bir "quit" mesajı yazar ve çıkar.
B sürecim bir değeri (A'dan gelen mesaj) okuyan, 10 ekleyen ve sonra sonucu (A'ya mesaj) yazan koşullu sonsuz bir döngüdedir. B bir "quit" mesajı okursa, derhal sona erer.
İletişimin tamamen eşzamanlı olduğunu göstermek istedim, bu yüzden hem A hem de B işlem döngülerinde bir gecikme getirdim.
ReadLine yordamının, girişi beklerken hem CPU'yu hem de dosya sistemini sürekli olarak kötüye kullanan sıkı bir döngüde olduğunu unutmayın. Döngüye bir PING gecikmesi eklenebilir, ancak daha sonra işlemler o kadar duyarlı olmayacaktır.
Hem A hem de B işlemlerini başlatmak için gerçek bir boru kullanıyorum. Ancak boru, hiçbir iletişimin geçmemesi nedeniyle işlevsel değildir. Tüm iletişim geçici "kanal" dosyaları üzerinden yapılır.
İşlemleri başlatmak için START / B'yi de kullanabilirdim, ancak daha sonra her ikisinin de ne zaman sonlanacağını tespit etmeliyim ki geçici "boru" dosyalarını ne zaman sileceğimi biliyorum. Boruyu kullanmak çok daha kolaydır.
Tüm kodu tek bir dosyaya koymayı seçtim - A ve B'yi başlatan ana komut dosyası ve A ve B kodu. Her işlem için ayrı bir komut dosyası kullanmış olabilirim.
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
--ÇIKTI--
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
Üst düzey bir dil ile yaşam biraz daha kolaydır. A ve B işlemleri için VBScript kullanan bir örnek aşağıdadır. İşlemleri başlatmak için hala toplu işi kullanıyorum. Ben çok serin yöntem de tarif kullanmak gömmek mümkün o ve geçici bir dosya kullanmadan bir toplu dosya içinde VBScript'i yürütmek? birden çok VBS komut dosyasını tek bir toplu iş komut dosyasına gömmek için.
VBS gibi daha yüksek bir dilde, A'dan B'ye bilgi iletmek için normal bir boru kullanabiliriz. B'den A'ya bilgi aktarmak için yalnızca tek bir geçici "boru" dosyasına ihtiyacımız var. işleminin B'ye bir "quit" iletisi göndermesi gerekmez. B işlemi dosya sonuna ulaşana kadar döngü yapar.
VBS uygun bir uyku fonksiyonuna erişim olması güzel. Bu, CPU'ya bir mola vermek için readLine işlevinde kolayca kısa bir gecikme yapmamı sağlar.
Bununla birlikte, readLIne içinde bir kırışıklık vardır. İlk başta, bazen readLine'ın stdin'de mevcut bilgileri algılayacağını ve B'nin satırı yazmayı bitirme şansı bulamadan hemen önce satırı okumaya çalışacağını anlayana kadar aralıklı hatalar alıyordum. Dosya sonu testi ile okuma arasında kısa bir gecikme getirerek sorunu çözdüm. 5 ms gecikme benim için hile gibi görünüyordu, ama ben sadece güvenli tarafında olmak için 10 ms için iki katına çıktı. Toplu işin bu sorunu yaşamaması çok ilginç. Bu konuyu kısaca tartıştık (5 kısa mesaj) 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>
Çıktı, saf "çözelti" ile aynıdır, ancak son "quit" hatları yoktur.