Пользователь
0,0
рейтинг
25 июня 2009 в 16:06

Разработка → Взаимодействие между несколькими .bat, мультиплеер на .bat


Бат-файлы лишены возможности передавать по сети какую-нибудь полезную информацию друг другу.

Нет сокетов, ну и ладно, зато есть простая работа с именованными областями данных, т.е. файлами. Создание и чтение однострочных текстовых файлов вообще упрощено до предела. Достаточно выполнить echo Text>file.txt и file.txt будет содержать строку «Text». Прочитать строку из файла можно так: set /p var=<file.txt (после выполнения переменная var будет содержать строку «Text»).

Итак, можно передавать информацию между батниками через файлы. А если эти файлы будут находиться на расшаренных сетевых ресурсах, то между собой вполне могут общаться батники, запущенные на различных компьютерах.

Вот небольшой пример клиент-серверного приложения, такого себе rexec для бедных.

файл rexec_server.bat:
set checkFolder=\\IMP5\PUBLIC_RW
:loop
@ping -n 2 127.0.0.1 > nul
@if not exist "%checkFolder%\!cmd" goto loop
@call "%checkFolder%\!command.bat" > "%checkFolder%\!result"
@del "%checkFolder%\!cmd"
@goto loop


файл rexec_client.bat:
@echo off
set checkFolder=\\IMP5\PUBLIC_RW

:mainloop
set /p c=^>
if "%c%"=="exit" exit
if "%c%"=="quit" exit
echo %c%>"%checkFolder%\!command.bat"
echo.>"%checkFolder%\!cmd"

:waitloop
ping -n 2 127.0.0.1 > nul
if exist "%checkFolder%\!cmd" goto waitloop
type "%checkFolder%\!result"
del "%checkFolder%\!result"
goto mainloop


Вот пример работы:


Делает оно следующее: rexec_server.bat ждёт от клиента командную строку и выполняет её на том компьютере, на котором он запущен. С клиентом он общается через расшаренную папку «\\IMP5\PUBLIC_RW» (разумеется, вам нужно будет заменить её на свою, если захотите поэкспериментировать). Чтобы клиент и сервер не пытались раньше времени прочитать файлы, которые сейчас для них пишутся, были предусмотрены файлы-флаги, которые служат только для того, чтобы обозначить, что информация уже сохранена полностью.

Ну и на закуску — мультиплеерная игра на .bat «крестики-нолики, три в ряд».
Здесь для сохранения целостности данных реализован механизм критических секций для блокирования попыток одновременного обращения к файлам.
Помните, что перед запуском нужно в строке «set FLAG_DIR=\\IMP5\SHARED_RW» указать свою расшаренную папку (кстати, через одну папку могут играться сразу несколько игр).

Файл xo.bat:
@echo off
cls
set FLAG_DIR=\\IMP5\SHARED_RW

call :create_chars

:restart
echo Please wait...
call :sys_utils init "%0"
set cmdPrefix=$p%__PID%

rem  ------- connecting --------

call :sys_utils enter_critical_section
cls
call :sys_utils fetch_flag ready_to_play
if "%RESULT%"=="" (
  call :sys_utils set_flag ready_to_play %cmdPrefix%
  set symbol=X
  set symbol2=O
  set server=1
) else (
  set cmdPrefix=%RESULT%
  call :sys_utils set_flag %RESULT%_client_ready ---
  set symbol=O
  set symbol2=X
  set server=0
)
call :sys_utils leave_critical_section

if "%server%"=="0" goto client1
  call :wait_for_client
  call :sys_utils set_flag %cmdPrefix%_server_ready_too ---
  goto skipClient1
:client1
  call :wait_for_server
  if "%serverFailure%"=="1" goto restart
:skipClient1

rem  ------- connected --------

call :clear_field
if "%server%"=="1" (set curMode=your_turn) else (set curMode=enemy_turn)

:main_game_loop
  cls
  call :check_win
  call :render_field

  if "%winSymbol%"=="%symbol%" goto you_win
  if "%winSymbol%"=="%symbol2%" goto enemy_win
  
  if not "%curMode%"=="your_turn" goto skipTurn1
    echo.
    echo Your are "%symbol%"
    echo.
    set /p tmp=Please enter <nul
    if "%f1%"=="1" set /p tmp=1, <nul
    if "%f2%"=="2" set /p tmp=2, <nul
    if "%f3%"=="3" set /p tmp=3, <nul
    if "%f4%"=="4" set /p tmp=4, <nul
    if "%f5%"=="5" set /p tmp=5, <nul
    if "%f6%"=="6" set /p tmp=6, <nul
    if "%f7%"=="7" set /p tmp=7, <nul
    if "%f8%"=="8" set /p tmp=8, <nul
    if "%f9%"=="9" set /p tmp=9, <nul
    echo or 'q' for quit
    echo.
    set /p "tmp=Your turn: "

    if "%tmp%"=="q" goto quit_game
    if "%tmp%"=="Q" goto quit_game

    call set varName=%%f%tmp%%%
    if not "%varName%"=="%tmp%" goto main_game_loop
    call set f%tmp%=%symbol%

    call :sys_utils set_flag %cmdPrefix%_%symbol%_move f%tmp%
    set curMode=enemy_turn
    goto main_game_loop
  :skipTurn1

  if not "%curMode%"=="enemy_turn" goto skipTurn2
    echo.
    echo Waiting for another player
    :wait_for_player0
      set /p tmp=.<nul
      ping -n 2 127.0.0.1 > nul
      call :sys_utils fetch_flag %cmdPrefix%_%symbol2%_move
    if "%RESULT%"=="" goto wait_for_player0

    echo %RESULT%

    if "%RESULT%"=="q" goto other_player_quit

    call set %RESULT%=%symbol2%
    set curMode=your_turn
    goto main_game_loop
  :skipTurn2

goto main_game_loop

:quit_game
  call :sys_utils set_flag %cmdPrefix%_%symbol%_move q
exit

:other_player_quit
  cls
  echo Other player has left the game.
  echo Press 'Enter' to search for another one.
  pause > nul
goto restart

:you_win
  echo.
  echo You Win
  echo.
  echo Press 'Enter'
  pause > nul
goto restart

:enemy_win
  echo.
  echo You Lose
  echo.
  echo Press 'Enter'
  pause > nul
goto restart

:wait_for_client
  echo Waiting for client
  :wait_for_client1
    set /p tmp=.<nul
    ping -n 2 127.0.0.1 > nul
    call :sys_utils fetch_flag %cmdPrefix%_client_ready
  if "%RESULT%"=="" goto wait_for_client1
exit /b

:wait_for_server
  echo Waiting for server
  set serverFailure=0
  set /a waitCnt=4
  :wait_for_server1
    set /a waitCnt-=1
    if "%waitCnt%"=="0" (
      set serverFailure=1
      exit /b
    )
    set /p tmp=.<nul
    ping -n 2 127.0.0.1 > nul
    call :sys_utils fetch_flag %cmdPrefix%_server_ready_too
  if "%RESULT%"=="" goto wait_for_server1
exit /b

:clear_field
  set "f1=1"
  set "f2=2"
  set "f3=3"
  set "f4=4"
  set "f5=5"
  set "f6=6"
  set "f7=7"
  set "f8=8"
  set "f9=9"
exit /b


:create_chars

  set "charX0= #   # ^|"
  set "charX1=  # #  ^|"
  set "charX2=   #   ^|"
  set "charX3=  # #  ^|"
  set "charX4= #   # ^|"
  set "charX5=-------+"

  set "charO0=  ###  ^|"
  set "charO1= #   # ^|"
  set "charO2= #   # ^|"
  set "charO3= #   # ^|"
  set "charO4=  ###  ^|"
  set "charO5=-------+"

  set "charXW0=.#...#.^|"
  set "charXW1=..#.#..^|"
  set "charXW2=...#...^|"
  set "charXW3=..#.#..^|"
  set "charXW4=.#...#.^|"
  set "charXW5=-------+"

  set "charOW0=..###..^|"
  set "charOW1=.#...#.^|"
  set "charOW2=.#...#.^|"
  set "charOW3=.#...#.^|"
  set "charOW4=..###..^|"
  set "charOW5=-------+"

  for %%i in (1,2,3,4,5,6,7,8,9) do call :create_empty_char %%i

exit /b

:create_empty_char
  set "char%10=       ^|"
  set "char%11=       ^|"
  set "char%12=   %1   ^|"
  set "char%13=       ^|"
  set "char%14=       ^|"
  set "char%15=-------+"
exit /b

:check_win
  set winSymbol=.
  call :check3 1 2 3
  call :check3 4 5 6
  call :check3 7 8 9
  call :check3 1 4 7
  call :check3 2 5 8
  call :check3 3 6 9
  call :check3 1 5 9
  call :check3 3 5 7
exit /b

:check3
  call set tmp1=%%f%1%%%%f%2%%%%f%3%%
  call set tmp2=%%f%1%%%%f%1%%%%f%1%%
  if "%tmp1%"=="%tmp2%" (
    call set "winSymbol=%%f%1%%"
    call set "f%1=%%f%1%%W"
    call set "f%2=%%f%2%%W"
    call set "f%3=%%f%3%%W"
  )
exit /b

:render_field
  call :render_line %f1% %f2% %f3%
  call :render_line %f4% %f5% %f6%
  call :render_line %f7% %f8% %f9%
exit /b

:render_line
   call echo %%char%10%%%%char%20%%%%char%30%%
   call echo %%char%11%%%%char%21%%%%char%31%%
   call echo %%char%12%%%%char%22%%%%char%32%%
   call echo %%char%13%%%%char%23%%%%char%33%%
   call echo %%char%14%%%%char%24%%%%char%34%%
   call echo %%char%15%%%%char%25%%%%char%35%%
exit /b


rem ----------------- atom --------------
:sys_utils
goto %1
exit /b

:init
  if "%FLAG_DIR%"=="" set FLAG_DIR=.
  set UNIQ_BAT_ID=%COMPUTERNAME%_%USERNAME%_%~n2
  set /A CRITICAL_SECTION_LEVEL=0

  call :enter_critical_section
  call :test_flag --null-- $pid$
  set /A __PID=%RESULT%
  if [%__PID%]==[0] set /A __PID=10000000
  if [%__PID%]==[] set /A __PID=10000000
  if [%__PID%]==[99999999] set /A __PID=10000000
  set /A __PID=__PID+1
  call :set_flag --null-- $pid$ %__PID% 
  call :leave_critical_section

  set UNIQ_BAT_ID=%UNIQ_BAT_ID%_pid%__PID%
exit /b

:set_flag
  call :enter_critical_section
  echo %3>"%FLAG_DIR%\%2"
  call :leave_critical_section
exit /b

:remove_flag
  call :enter_critical_section
  if exist "%FLAG_DIR%\%2" del "%FLAG_DIR%\%2"
  call :leave_critical_section
exit /b

:fetch_flag
  call :enter_critical_section
  set "RESULT="
  if exist "%FLAG_DIR%\%2" (
    set /p RESULT=<"%FLAG_DIR%\%2"
    del "%FLAG_DIR%\%2"
  )
  call :leave_critical_section
exit /b

:test_flag
  call :enter_critical_section
  set "RESULT="
  if exist "%FLAG_DIR%\%2" set /p RESULT=<"%FLAG_DIR%\%2"
  call :leave_critical_section
exit /b

:enter_critical_section
  set /A CRITICAL_SECTION_LEVEL=CRITICAL_SECTION_LEVEL+1
  if not [%CRITICAL_SECTION_LEVEL%]==[1] exit /b

  set /A __WAIT_CNT=500

  :wait_enter_critical_section
  set /A __WAIT_CNT=__WAIT_CNT-1
  if [%__WAIT_CNT%]==[0] del "%FLAG_DIR%\$cs$_*"
  if exist "%FLAG_DIR%\$cs$_*" goto wait_enter_critical_section

  echo.>"%FLAG_DIR%\$cs$_%UNIQ_BAT_ID%"
  set /A __CNT=0
  for %%i in ( "%FLAG_DIR%\$cs$_*" ) do set /a __CNT=__CNT+1
  if [%__CNT%]==[1] goto all_right_1
    del "%FLAG_DIR%\$cs$_%UNIQ_BAT_ID%"
    goto wait_enter_critical_section
  :all_right_1
exit /b

:leave_critical_section
  set /A CRITICAL_SECTION_LEVEL=CRITICAL_SECTION_LEVEL-1
  if [%CRITICAL_SECTION_LEVEL%]==[0] del "%FLAG_DIR%\$cs$_%UNIQ_BAT_ID%"
exit /b

:EOF
Алексей Борисов @Imp5
карма
135,0
рейтинг 0,0
Реклама помогает поддерживать и развивать наши сервисы

Подробнее
Реклама

Самое читаемое Разработка

Комментарии (100)

  • +148
    Автор сумасшедший гик! В добром смысле слова :)
    • +9
      Может ему просто скучно иногда? :)
    • +8
      Инфо из профайла :)

      Состоит в:

      * Ненормальное программирование

      • +9
        Логично — иначе как бы он в этот блог написал? :)
        • +2
          Ха ха. Точно, а я даже не заметил.
    • +1
      Может стоит перенести в «Я безумный»? :)
      • +8
        Надо подумать.
        А то у меня тут сейчас 15 минут пешком до моря, а я чёрт знает чем занимаюсь =)
        • +1
          О боги! Вы действительно безумный :D
    • 0
      А по-моему, в злом (:
  • +7
    хардкор
    • +6
      хардкоД :)
  • +26
    Кстати, если заиспользовть ftp, то можно сделать игру через интернет.
    • –2
      Для этого можно воспользоваться программой FtpDrive которая монтирует FTP как жёсткий диск.
      • +6
        Даже не обязательно FtpDrive использовать =)
        Стандартному ftp.exe можно скармливать последовательность команд.
      • +1
        Эм, а чего минусуете? С фтпдрайвом вообще ничего модифицировать не надо и получится интернет-игра.
        PS: я не автор этого продукта, да и кажется он бесплатен, так что рекламы тут видеть не надо
        • +1
          потому что это не хардкор. вот то что нарисовал автор в топике — это хардкор, и если утда добавить ftp, то убдет только хардкорнее. а FtpDrive это уже антихардкор.
        • +3
          а еще можно поставить RAdmin и не париться с батниками.
          Минусуют, потому что использовать сторонние программы, кроме блокнота, в данном примере не спортивно :)
  • +3
    Даешь Wolfenstein и Mario на bat!
    • +2
      Rogue :)
  • +19
    Вы маньяк =) На таких земля держится =)
  • +1
    не думал, что в 21-м веке… и такое… :)
  • +13
    И для кого только этот Microsoft всякие повершелы выдумывает? (:
  • НЛО прилетело и опубликовало эту надпись здесь
  • +4
    Вы суровый человек!!!
  • +8
    Нет слов!) Те кто пробовал писать более-менее серьезные bat'ники понимают…
  • +5
    Автору однозначно путь на руборд в ветку с решением задачек на .bat :) Там порой бывают дурные решения, да и проблемы часто ооочень не тривиальные.
    • +2
      О! спасибо, не знал про такое =)
      • +2
        Более того, вас там будут рады видеть, уверяю!
        • 0
          Кажется, люди там на много более продвинутее меня.
          Даже стыдно что-то писать туда перед тем как весь тред не прочитаю. =)
          • 0
            Только это хотел сказать =D Я сам там только читателем бываю… Страшно даже слово сказать с моими универскими знаниями. Вот где живут настоящие извращенцы =) но лучше пусть извращаются с кодом, чем с кем-то =D

            Но вообще хотелось бы сказать, что ограниченность во всяком смысле этого слова заставляет мыслить нетривиально, что дает новый толчок к развитию мозга. Вот за что я люблю BAT. Сам займусь извращениями когда будет время.
  • +3
    даешь графический 3d-движок на bat! :)
    • +2
      … котрый как в том старом топике о картинках генерированных с помощью .bat выводит цветное изображение в файл :)
    • 0
      танчики? ..)))

      P.S.: кстати, жду не дождусь, когда сервак начнет справляться…
  • +6
    Сильно!

    «Nemo: Java — уг, ассемблер рулед
    Nemo: гы гы гы
    Stranger: Ага, посмотрю я как ты на ассемблере живую трансляцию будешь делать
    Stranger: Внуки бегали и смеялись, а старый кряхтящий немов все писал и писал, даже не понимая, откуда внуки...»

    из этой серии=))))))
    • +3
      не факт, что среднестатистический делфист напишет крестики-нолики быстрей, чем этот человек на .bat ,.)
      • +1
        дык просто не в этом дело. ни у кого в голове даже мысли не было на батнике писать сетевые крестики нолики=))))
  • +13
    Ох мать моя. Побольше бы таких маньяков на хабре :)
  • 0
    Кто б мог подумать — такое на .bat! красота :)
  • 0
    OMG O_o
  • 0
    Осталось ещё бота написать :)
  • +7
    Жесть, вот что бывает, когда свободного времени слишком много =)
    • +2
      … и есть голова на плечах. :)
  • +2
    Это очень жестоко и сурово, пять баллов.
    Только хочу напомнить что кроме простого BAT, windows поддерживает мощнейший WSH — Windows scripting Host, которым эти самые сетевые диски можно монтировать и вообще выполнять произвольный код на VB/JS. Кажется, это было бы немного полезнее.
  • 0
    Что-то она у меня глючит сильно. Рассигхронизация происходит.
    • 0
      Какие симптомы?
      Какая версия windows?
      • 0
        Windows XP. На обоих клиентах висит надпись, что надо сделать ход. А после выхода (через Ctrl-C), игра заявляет, что нашла клиента, который сделал ход «X» на 5, можно сделать сколько угодно своих ходов и даже выиграть противника, у которого вечная «Х» на 5.
        • 0
          ужс…
          а папка расшарена на запись для всех?
          в строке set FLAG_DIR=\\IMP5\SHARED_RW в конце не должно быть слеша.
          а если удалить из расшаренной папки файлы $cs$_* и $pid$?
          • 0
            Да, на всех. Если удалить становиться лучше, но через какое-то время опять всё плохо.
            • 0
              Эх, жаль, что перед релизом не было возможности провести масштабное тестирование.
              • +1
                Увы, особо времени разбираться сейчас нет, а так — с радостью покопался бы.
  • –1
    У меня пишет вот такую ошибку
    Не удается найти \\prog\tmp\$cs$_PROG_Vladimir_xo
    • 0
      Всё получилось
  • НЛО прилетело и опубликовало эту надпись здесь
  • 0
    интересно, а сколько людей прочитав статью сразу же решили попробывать? :)
    • +2
      Мы с коллегами тут же про«бета»тестили. Всё пашет!
  • +1
    Самое лучшее что я видел по программированию в последнее время, нужно сохранить для потомков.
  • +2
    Меня всегда интересовал вопрос: Почему Билл Гейтс, уместивший Бейсик для Альтаира в 4Кб, не пожелал снабдить DOS (как и последующие свои ОС) нормальным скриптовым языком, да хоть на основе того же бейсика?
    • +2
      Срочно гуглить Windows scripting Host. Как минимум с Windows 98 начался, а то и раньше.
      • 0
        Только через 15 лет он спохватился :)
        • 0
          Насколько я понимаю, именно тогда он и стал реально нужен. В бытность свою в MS DOS и Win 3.11 обходился батниками, более широкого функционала не требовалось. Хотя, это конечно я со своей колокольни.
    • 0
      gwbasic.exe шел уже с DOS 3.1 это насколько я помню

      с 5й версии шел уже qbasic.exe
      • 0
        Это таки скриптовый язык?
        • 0
          А что в нем нескриптового? :)

          Он идет с системой по-умолчанию. Он интерпретируется.

          Чем вызов «wshost.exe script.vbs» отличается от «gwbasic.exe script.bas»? :)
  • +7
    Удивительно, но никто на этот раз не написал «Мсье знает толк в извращениях»
    • +14
      Потому что все уже поняли, что мсье таки знает толк в извращениях.
    • +1
      вот верите нет, еле сдержался=)))
  • НЛО прилетело и опубликовало эту надпись здесь
  • +1
    Мега-респект!!! Прямо нереальное программирование)

    p.s. это баг, что ничьи нет?)
    • +1
      баг =)
  • +15
    Не так быстро, у меня ещё Мандельброт досчитывается ;)
  • +6
    Я Вас боюсь.
  • 0
    Простите, а сколько времени ушло создания этого? %)
    • +2
      где-то 3 дня в свободное время
  • –1
    Интересно, неужели за последние 30 лет до этого никто не додумался? Что-то мне подсказывает, что во времена доса таким просто не могли не баловаться )
  • 0
    Даешь морской бой! ;-)

    P.S. ping == pause?
    • +1
      >ping == pause?
      да
  • 0
    это офигенно круто! я внукам покажу лет через 25!
  • 0
    автору респект, надо быть либо гением либо идиотом, что-бы придумать подобное, но пологаю автор относится к первым… :-)
  • 0
    ацкий ад!
    нереально круто =)
  • 0
    мм… теперь такое да на баше осуществить)
    • +3
      После веб-сервера на bash-е и тетриса на sed-е (написанного девушкой, кстати :)) я уже ничему не удивлюсь %)
  • 0
    А я думал будто это я извращенец с сапером на фокс про! ))
  • НЛО прилетело и опубликовало эту надпись здесь
    • 0
      Под винду он вроде бы тоже есть, но такое решение требует стороннего софта, так что это не Ъ. :)
      • НЛО прилетело и опубликовало эту надпись здесь
  • +1
    Бат-файлы лишены возможности передавать по сети какую-нибудь полезную информацию друг другу.
    Интересно, сколько человк прочитав эту первую строчку подумали про расшаренный текстовый файл с данными? :)
    Автору респект.
    Морской бой на порядок сложнее будет.
    • 0
      Я грешным делом, испорченный никсами, про сокеты подумал :)
  • НЛО прилетело и опубликовало эту надпись здесь
  • 0
    спасибо. это очень круто.
    не знал про set /p var=<file.txt.
    тоже спасибо.
  • 0
    Кстати, а ведь еще можно использовать .bat-скрипты совместо с замечательной программой debug — в смысле совмещения bat с асмом :)
    Или это уже будет не тру-кодинг? :)
    • 0
      Конечно же тру =)
      Компилятор на батниках без debug — так вообще сложно сделать.
      Но как выяснилось в обсуждении habrahabr.ru/blogs/crazydev/62043/ — debug.exe есть не у всех.
      • 0
        debug, сжатый UPX-ом весит примерно 14,5 КБ — думаю, скачать его не будет большой проблемой.

        Ну а при помощи прерывания 10h вполне можно писать графические игры, а следовательно, там уже и до Mario c Wolfenstein на батниках недалеко :)
      • 0
        Собственно вот :))

        <code>
        @echo off
        @goto end
        a 100
        push es
        mov ax, A000
        mov es, ax
        xor ax, ax
        mov al, 13
        int 10
        mov ax, A000
        xor ax, ax
        mov cx, FA00
        mov al, cl
        stosb
        loop 0114
        mov ax, 100
        int 21
        xor ax, ax
        mov al, 3
        int 10
        int 20
        
        rcx
        124
        n vid.com
        w
        q
        
        :end
        pushd %temp%
        cd %temp%
        debug < "%~sf0" >NUL
        popd
        %temp%\vid.com
        del %temp%\vid.com
        </code>


        Почему-то без записи во временный файл не получилось, хотя такая возможность по идее должна быть.

        К тому же откопал совершенно восхитительную вещь:
        www.robvanderwoude.com/debug.php

        Думаю вам будет очень интересно почитать :)
        • 0
          Круто! Спасибо за ссылку.
  • 0
    О Божэ! Мы ваще блондинки рядом с Вами!
  • 0
    В этом rexec фундаментальная уязвимость — позволяет выполнить любую команду на удаленной машине с правами пользователя. Не проще ли ограничить его определенным списком?
  • 0
    Интересно яку еще дикую идею можно реализовать с помощью bat файла.
  • 0
    Я всегда считал виндовую консоль жутко ущербной в сравнении с никсами в особенности… теперь даже не знаю…
  • 0
    XOXO
  • 0
    Я щас Аспирант. Буду учить молодежь программировать Bat-файлы. В качестве примера для мотивации дам этот пример! Пусть учатся =)

Только зарегистрированные пользователи могут оставлять комментарии. Войдите, пожалуйста.