ไม่เพียง แต่จะสามารถทำได้มันสามารถทำได้โดยไม่ต้องทำอะไรเลยนอกจากเป็นไฟล์แบทช์! :-)
ปัญหาสามารถแก้ไขได้โดยใช้ไฟล์ชั่วคราวเป็น "ไพพ์" การสื่อสารสองทิศทางต้องการไฟล์ "pipe" สองไฟล์
กระบวนการ A อ่าน stdin จาก "pipe1" และเขียน stdout ไปที่ "pipe2"
กระบวนการ B อ่าน stdin จาก "pipe2" และเขียน stdout เป็น "pipe1"
เป็นสิ่งสำคัญที่ไฟล์ทั้งสองจะมีอยู่ก่อนที่จะเริ่มกระบวนการใดกระบวนการหนึ่ง ไฟล์ควรจะว่างเปล่าตั้งแต่เริ่มต้น
หากไฟล์แบตช์พยายามอ่านจากไฟล์ที่เกิดขึ้นที่ส่วนท้ายของปัจจุบันไฟล์นั้นจะไม่ส่งคืนอะไรเลยและไฟล์จะยังคงเปิดอยู่ ดังนั้นรูทีน readLine ของฉันจะอ่านอย่างต่อเนื่องจนกว่ามันจะได้ค่าที่ไม่ว่างเปล่า
ฉันต้องการอ่านและเขียนสตริงว่างดังนั้นรูทีน writeLine ของฉันจะต่อท้ายอักขระพิเศษที่ readLine ดึงออก
กระบวนการ A ของฉันควบคุมการไหล มันเริ่มต้นสิ่งต่าง ๆ โดยการเขียน 1 (ข้อความถึง B) จากนั้นเข้าสู่ลูปที่มีการวนซ้ำ 10 ครั้งที่มันอ่านค่า (ข้อความจาก B) เพิ่ม 1 และเขียนผลลัพธ์ (ข้อความถึง B) ในที่สุดมันจะรอข้อความสุดท้ายจาก B จากนั้นเขียนข้อความ "exit" ไปที่ B และออก
กระบวนการ B ของฉันอยู่ในวงวนไม่มีเงื่อนไขที่อ่านค่า (ข้อความจาก A) เพิ่ม 10 จากนั้นเขียนผลลัพธ์ (ข้อความถึง A) หาก B เคยอ่านข้อความ "เลิก" แล้วมันจะยุติลงทันที
ฉันต้องการแสดงให้เห็นว่าการสื่อสารนั้นเป็นแบบซิงโครนัสอย่างสมบูรณ์ดังนั้นฉันจึงแนะนำการหน่วงเวลาทั้งกระบวนการ A และ B
โปรดทราบว่าโพรซีเดอร์ readLine อยู่ในลูปที่ จำกัด ซึ่งใช้งาน CPU และระบบไฟล์อย่างต่อเนื่องในขณะที่รออินพุต การหน่วงเวลา PING สามารถเพิ่มลงในลูปได้ แต่จากนั้นกระบวนการจะไม่ตอบสนอง
ฉันใช้ไพพ์จริงเพื่อความสะดวกในการเปิดทั้งกระบวนการ A และ B แต่ไปป์นั้นใช้งานไม่ได้เพราะไม่มีการสื่อสารผ่านมัน การสื่อสารทั้งหมดผ่านไฟล์ "ไปป์" ชั่วคราวของฉัน
ฉันสามารถใช้ START / B เพื่อเริ่มกระบวนการได้เช่นกัน แต่ฉันต้องตรวจสอบเมื่อทั้งคู่ยุติเพื่อให้ฉันรู้ว่าเมื่อใดควรลบไฟล์ "ไพพ์" ชั่วคราว มันง่ายกว่ามากในการใช้ท่อ
ฉันเลือกที่จะใส่รหัสทั้งหมดในไฟล์เดียว - สคริปต์หลักที่เปิดตัว A และ B เช่นเดียวกับรหัสสำหรับ A และ B ฉันสามารถใช้ไฟล์สคริปต์แยกต่างหากสำหรับแต่ละกระบวนการ
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
ชีวิตง่ายขึ้นเล็กน้อยด้วยภาษาระดับที่สูงขึ้น ด้านล่างเป็นตัวอย่างที่ใช้ VBScript สำหรับกระบวนการ A และ B ฉันยังคงใช้แบทช์เพื่อเปิดกระบวนการ ฉันใช้วิธีที่ยอดเยี่ยมมากที่อธิบายไว้ที่เป็นไปได้ที่จะฝังและเรียกใช้ VBScript ภายในไฟล์แบตช์โดยไม่ต้องใช้ไฟล์ชั่วคราวหรือไม่? เพื่อฝังสคริปต์ VBS หลายรายการภายในสคริปต์ชุดเดียว
ด้วยภาษาที่สูงกว่าเช่น VBS เราสามารถใช้ไพพ์ปกติเพื่อส่งผ่านข้อมูลจาก A ถึง B เราต้องการไฟล์ "ไพพ์" ชั่วคราวเพียงไฟล์เดียวเพื่อส่งข้อมูลจาก B กลับสู่ A เนื่องจากตอนนี้เรามีไพพ์ที่ใช้งานได้แล้ว กระบวนการไม่จำเป็นต้องส่งข้อความ "ออกจากระบบ" ไปยัง B. กระบวนการ B จะวนซ้ำจนกว่าจะถึงจุดสิ้นสุดไฟล์
มันเป็นเรื่องดีที่มีการเข้าถึงฟังก์ชั่นการนอนหลับที่เหมาะสมใน VBS สิ่งนี้ช่วยให้ฉันสามารถแนะนำการหน่วงเวลาสั้น ๆ ในฟังก์ชั่น readLine เพื่อให้ CPU หยุดพักได้
อย่างไรก็ตามมีหนึ่งรอยย่นใน readLIne ในตอนแรกฉันได้รับความล้มเหลวเป็นระยะ ๆ จนกระทั่งฉันรู้ว่าบางครั้ง readLine จะตรวจสอบข้อมูลที่มีอยู่ใน stdin และจะพยายามอ่านบรรทัดทันทีก่อนที่ B จะมีโอกาสเขียนเส้นให้เสร็จ ฉันแก้ไขปัญหาด้วยการแนะนำการหน่วงเวลาสั้น ๆ ระหว่างการทดสอบสิ้นสุดไฟล์และการอ่าน การหน่วงเวลา 5 มิลลิวินาทีดูเหมือนจะเป็นการหลอกลวงสำหรับฉัน แต่ฉันเพิ่มเป็นสองเท่าถึง 10 มิลลิวินาทีเพื่อให้ปลอดภัย เป็นที่น่าสนใจมากว่าแบทช์ไม่ประสบปัญหานี้ เรากล่าวสั้น ๆ นี้ (5 โพสต์สั้น) ที่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>
เอาต์พุตเหมือนกันกับโซลูชันแบตช์บริสุทธิ์ยกเว้นบรรทัด "ออกจาก" ขั้นสุดท้ายจะไม่มี