Что нового

Передача данных между компьтерами

The_Immortal

Новичок
Сообщения
84
Репутация
4
Всех приветствую!

Имеется два компьютера: "принт-клиент" и "принт-сервер". Задача принт-клиента отправлять (копировать) на принт-сервер файлы. Задача принт-сервера - распечатывать эти файлы. Компьютеры связаны по сети.

1. На принт-сервере в бесконечном цикле запущен скрипт, который с определенной периодичностью проверяет наличие файлов для распечатки. Можно ли как-то обойтись без постоянно запущенного скрипта? Т.е. принт-клиент отправляет файл и сразу же посылает принт-серверу запрос на распечатку? Нет ли какого-либо инструментария для такого?
Дело в том, что сервер из себя представляет всего-лишь виртуальную машину на слабом клиентском компьютере. Поэтому ресурсы ЦП хотелось бы экономить.

2. Некоторые файлы требуют дополнительных параметров: кол-во копий, ориентация, диапазон страниц и т.п. Принт-клиент для этого создает на принт-сервере дополнительный текстовый файл, где указываются все эти параметры в следующем виде:
Код:
5 ;CopyCount
0 ;Orientation
...
Полагаю, что без промежуточного файла в этом случае не обойтись (или я не прав?). Но такой текстовый файл очень не удобен в плане обработки. Может есть более удачные варианты? Ini-файлы, например...

В общем, буду благодарен, если подправите концепцию и/или подскажите по возникшим вопросам.


Большое спасибо!
 
Автор
T

The_Immortal

Новичок
Сообщения
84
Репутация
4
The_Immortal [?]
На принт-сервере в бесконечном цикле запущен скрипт, который с определенной периодичностью проверяет наличие файлов для распечатки. Можно ли как-то обойтись без постоянно запущенного скрипта?Дело в том, что сервер из себя представляет всего-лишь виртуальную машину на слабом клиентском компьютере. Поэтому ресурсы ЦП хотелось бы экономить.
Как и предполагалось...
Код:
#Include <FileOperations.au3>

$gWatchFolder = "C:\ToPrint\"

While true
	Local $sFileList = _FO_FileSearch($gWatchFolder, 'doc|docx|xls|xlsx|pdf', True, 0, 0, 1, 0)
	If @error Then ContinueLoop
    Sleep(5000)
WEnd
- код, естественно, урезан, но именно эта часть нагружает ЦП стопроцентно. Можно ли как-то снизить нагрузку или это неизбежно? Если нельзя, то тогда я вообще не понимаю, как у нас в фоне на постоянной основе работают множество служб и при этом не нагружают так ЦП... :scratch:
 

inververs

AutoIT Гуру
Сообщения
2,135
Репутация
465
Вы можете закэшировать время последнего изменения папки C:\ToPrint\ и как только оно изменилось - делать _FO_FileSearch

Плюс, у вас не в том месте пауза стоит, смотрите внимательнее что будет если @error
 
Автор
T

The_Immortal

Новичок
Сообщения
84
Репутация
4
inververs, да, паузу не туда впихнул, когда урезал код, спасибо!
А насчет кэширования изменений - не подскажите какими функциями пользоваться? Я честно поискал, но ничего не нашел :(
 

inververs

AutoIT Гуру
Сообщения
2,135
Репутация
465
The_Immortal [?]
А насчет кэширования изменений - не подскажите какими функциями пользоваться?
Код:
FileGetTime
, получаешь строку в виде YYYYMMDDHHMMSS, сохраняешь ее, в цикле опять получаешь ее, сравниваешь и если они отличаются, значит папка изменилась, проводишь сканирование.
 
Автор
T

The_Immortal

Новичок
Сообщения
84
Репутация
4
inververs, думаете это сильно снизит нагрузку?
 

inververs

AutoIT Гуру
Сообщения
2,135
Репутация
465
Если папка меняется очень быстро, то не снизит.
 

Prog

Продвинутый
Сообщения
537
Репутация
65
Чтобы снизить нагрузку на процессор, нужно использовать WinAPI функцию FindFirstChangeNotification и ждать события используя функцию WaitForSingleObject.
 
Автор
T

The_Immortal

Новичок
Сообщения
84
Репутация
4
Prog, благодарю за идею, но есть подозрение, что этот способ по сути аналогичен тому, что предложил уважаемый inververs, поэтому на разнице в нагрузке это сильно не скажется. Но я в любом случае попробую и то, и то.

Спасибо большое!
 

Prog

Продвинутый
Сообщения
537
Репутация
65
Функция WaitForSingleObject с параметром INFINITE останавливает текущий поток до возникновения события объекта, т. е. папка постоянно не проверяется на наличие новых файлов. Событие произойдет при изменении содержимого папки. Это работает на уровне системы.
 
Автор
T

The_Immortal

Новичок
Сообщения
84
Репутация
4
Prog, вкратце получилось так:

Код:
#include <WinAPIEx.au3>

$gWatchFolder = "C:\ToPrint\"

Global $hDir = _WinAPI_FindFirstChangeNotification($gWatchFolder, $FILE_NOTIFY_CHANGE_FILE_NAME)

While true
    _WinAPI_WaitForSingleObject($hDir)
	ConsoleWrite('A file was created, renamed, or deleted in the directory.' & @CRLF)
    _WinAPI_FindNextChangeNotification($hDir)
WEnd

Func OnAutoItExit()
	_WinAPI_FindCloseChangeNotification($hDir)
	ConsoleWrite('Bye-bye!' & @CRLF)
EndFunc


Хотел поинтересоваться чем чревато невыполнение FindCloseChangeNotification? Дело в том, что если скрипт у меня завершается, то происходит это аварийно... Соответственно, OnAutoItExit() не срабатывает...

И ещё: Вы не в курсе насчет RegisterWaitForSingleObject? Где-то читал (см. ниже), что эта штука намного лучше по сравнению с WaitForSingleObject, но я так и не понял чем... У Вас не было опыта работы с данной функцией?

It's pretty straight-forward, WaitForSingleObject() blocks a thread. It is consuming a megabyte of virtual memory and not doing anything useful with it while it is blocked. It won't wake up and resume doing useful stuff until the handle is signaled.

RegisterWaitForSingleObject() does not block a thread. The thread can continue doing useful work. When the handle is signaled, Windows grabs a thread-pool thread to run the code you specified as the callback. The same code you would have programmed after a WFSO call. There is still a thread involved with getting that callback to run, the wait thread, but it can handle many RWFSO requests.

So the big advantage is that your program can use a lot less threads while still handling many service requests. A disadvantage is that it can take a bit longer for the completion code to start running. And it is harder to program correctly since that code runs on another thread. Also note that you don't need RWFSO when you already use overlapped I/O.

С английским вроде как проблем не испытываю, однако полного понимания все равно не наступило :-\ Якобы WaitForSingleObject создает свой поток, блокирует его и никого туда не подпускает, а RegisterWaitForSingleObject подсасывается к уже существующему в ОС потоку, который во всю функционирует. Минус WaitForSingleObject - распоряжение ресурсами непрактичным образом, у RegisterWaitForSingleObject - всё наоборот. Минус RegisterWaitForSingleObject - долгое "просыпание" при поступлении сигнала, WaitForSingleObject - схватывает моментально, ибо его поток только и создан для ожидания этого сигнала.

Так?

"And it is harder to program correctly since that code runs on another thread." - а это я вообще не понял... В чём там сложность?
 

Prog

Продвинутый
Сообщения
537
Репутация
65
Где там написано что создается поток? Из цитаты: blocks a thread т. е. функция блокирует текущий поток до возникновения события, а RegisterWaitForSingleObject этого не делает.
 
Автор
T

The_Immortal

Новичок
Сообщения
84
Репутация
4
Prog, тогда получается, что функцию RegisterWaitForSingleObject действительно выгоднее использовать.

А с этим не подскажете:[?]
чем чревато невыполнение FindCloseChangeNotification? Дело в том, что если скрипт у меня завершается, то происходит это аварийно... Соответственно, OnAutoItExit() не срабатывает...
? В данном случае поток не разблокируется?
 

firex

AutoIT Гуру
Сообщения
943
Репутация
208
The_Immortal
Вам бы MSDN почитать, а не о "нерациональном распоряжении ресурсов у функции WaitForSingleObject" думать.
WaitForSingleObject помечает поток как alertable. В это время, к примеру, потоком обрабатываются APC. Пока поток "приостановлен" этой функцией до него вы конечно не достучитесь, а при некоторых обстоятельствах он может попасть и в DEADLOCK. Именно поэтому я не рекомендую использовать ее в связке с INFINITY

В вашем случае достаточно задать Timeout и обработать результат (WAIT_OBJECT_0).
 

Yashied

Модератор
Команда форума
Глобальный модератор
Сообщения
5,379
Репутация
2,724
Обратите внимание на RDC UDF.
 

Prog

Продвинутый
Сообщения
537
Репутация
65
The_Immortal [?]
тогда получается, что функцию RegisterWaitForSingleObject действительно выгоднее использовать.
Тогда вернемся к тому с чего начали.
[?]
На принт-сервере в бесконечном цикле запущен скрипт, который с определенной периодичностью проверяет наличие файлов для распечатки.
Придется в бесконечном цикле проверять наличие события.

WaitForSingleObject приостановит поток до возникновения события и нагрузка на процессор будет минимальной.
 
Автор
T

The_Immortal

Новичок
Сообщения
84
Репутация
4
[?]
Функция WaitForSingleObject с параметром INFINITE останавливает текущий поток до возникновения события объекта, т. е. папка постоянно не проверяется на наличие новых файлов.
[?]
некоторых обстоятельствах он может попасть и в DEADLOCK. Именно поэтому я не рекомендую использовать ее в связке с INFINITY
Честно говоря, я запутался - стоит ли мне использовать INFINITE или нет? Какова вероятность попадания в этот DEADLOCK?
 

robertocm

Новичок
Сообщения
1
Репутация
0
Здесь приведена адаптация из примера файла справки для функции _WinAPI_FindFirstChangeNotification

Код:
#include <WinAPIEx.au3>

$gWatchFolder = "C:\Documents and Settings\XP\Escritorio\Nueva carpeta"

Global $hDir = _WinAPI_FindFirstChangeNotification($gWatchFolder, $FILE_NOTIFY_CHANGE_FILE_NAME)

Local $iID, $bBoolean = False
While 1
    Sleep(1000)
	;Adapted from Help File example for _WinAPI_FindFirstChangeNotification function
	;My tests without the second parameter seems to have the issue 'can't exit normally' described here:
    ;https://www.autoitscript.com/forum/topic/180602-readdirectorychangesw-exit/
    $iID = _WinAPI_WaitForSingleObject($hDir, 0)
    Switch $iID
        Case 0 ; WAIT_OBJECT_0
			If $bBoolean = True Then
			   $bBoolean = False
			Else
			   $bBoolean = True
               ConsoleWrite('A file was created, renamed, or deleted in the directory.' & @CRLF)
			   Beep(400,50)
			EndIf
        Case Else
            ContinueLoop
    EndSwitch
    If Not _WinAPI_FindNextChangeNotification($hDir) Then
        MsgBox(0, 'Error', 'Unexpected error.')
        Exit
    EndIf
WEnd

Func OnAutoItExit()
    _WinAPI_FindCloseChangeNotification($hDir)
    ConsoleWrite('Bye-bye!' & @CRLF)
EndFunc
 

Garrett

Модератор
Локальный модератор
Сообщения
3,999
Репутация
967
robertocm

Предупреждение За нарушение правил форума (пункт В.11):
Любые отрывки AutoIt кода необходимо заключать в тег [autoit]
autoit.gif
(подробнее), а обычный код соответственно в тег [code]
code.gif
(подробнее). Также большие выдержки текста помещайте под тег [spoiler]
spoiler.gif
(подробнее), там где это поддерживается естественно. Как в случае с названием темы, также короткое и эргономичное сообщение привлекает больше внимания, и шансы на получение конкретного ответа увеличиваются.


С уважением, ваш Глобальный модератор.
 
Верх