HukpoFuJl
AццkuЙ HukpoFuJl
- Сообщения
- 98
- Репутация
- 38
Вот посетила меня безумная идея сделать вот такой вот менеджер закачек... т.к. я не любитель выкладывать исходники своих полноценно доделаных программ - буду выкладывать свои наработки, авось кому и сгодятся...
Система пока примитивная очень, даже многопоточностью назвать сложно, в общем алгоритм такой:
1. Проверяется размер файла, делиться на куски по 10 000 байт.
2. Разбивается на группы по 5 кусков.
3. Отправляется 5 запросов на закачку первых 5-ти частей.
4. Дожидается пока будут закачаны все первые 5 частей, по очереди каждую часть.
5. Записывает части по мере загрузки в файл.
6. Отсылает 5 запросов на закачку следующих 5-ти частей.
7. Дожидается пока будут закачаны эти 5 частей.
....(и т.д. по циклу)
N. Закрывает файл
Вот такой скромный алгоритм... Если есть интерес у окружающих - буду выкладывать по мере дорабатываемости... Если интереса нету - значит не судьба
ЗЫ: курсивом выделил то, над чем собираюсь работать =)
ДОПОЛНЕНИЕ: Было выявлено, что данный код не рабочий. (подробнее в сообщениях 6 и 7)
И так, раз мы многопоточности так и не добились - то пока что предлагаю подумать о докачке... А точнее сказать я о ней уже подумал ;)
Вот вам пример докачивающего скрипта, при запуске указываете прямую ссылку на файл - начинается простая загрузка (обычным InetGet).
Если прервать работу скрипта (например Ctrl+Break в SciTE) и запустить скрипт заново, указав ту же ссылку и тот же файл (не докачанный) то выскочит мес-бокс, с вопросом "Докачать?", жмете да и файл докачивается (подробнее в комменте скрипта).
Код:
$link = InputBox("Insert link",'Вставьте сюда ссылку на файл','')
$fSize = InetGetSize ($link)
If $fSize = 0 Then
MsgBox (0,'Error','Нету такого файла.')
Exit
EndIf
$file_path = FileSaveDialog ( "", "::{450D8FBA-AD25-11D0-98A8-0800361B1103}", "All (*.*)")
$file = FileOpen ($file_path,10)
$req_max = InputBox("Потоки",'Сколько одновременно использовать потоков?','5')
$req_all = Ceiling($fSize/10000)
If $req_all > $req_max Then
$req_sets = Ceiling($req_all/$req_max)
Else
$req_sets = 1
EndIf
Dim $reqS[$req_sets*$req_max+1]
$reqS[0]=$req_all
Dim $tempS[$req_sets*$req_max+1]
$tempS[0]=$req_all
For $req_sets_cur = 1 To $req_sets
For $i = $req_sets_cur*$req_max-$req_max+1 To $req_sets_cur*$req_max
If $i > $req_all Then ExitLoop
$reqS[$i] = _request($i)
Next
For $i = $req_sets_cur*$req_max-$req_max+1 To $req_sets_cur*$req_max
If $i > $req_all Then ExitLoop
$reqS[$i].WaitForResponse
FileWrite ($file,$reqS[$i].ResponseBody)
TrayTip ('Закачка',"Загружено "&Round(FileGetSize($file_path)/1024)&"Кб из "&Round($fSize/1024)&"Кб",200)
Next
Next
FileClose ($file)
Func _request($num)
$host = StringFindSE ($link,'http://','/',1,1)
$oHTTP = ObjCreate("WinHttp.WinHttpRequest.5.1")
$oHTTP.Open("GET", $link)
$oHTTP.SetRequestHeader("Host",$host)
$oHTTP.SetRequestHeader("Accept", "*/*")
$oHTTP.SetRequestHeader("User-Agent", "Mozilla/4.0 (compatible; MSIE 5.0; Windows 98)")
$oHTTP.SetRequestHeader("Range", "bytes="&$num*10000-10000&"-"&$num*10000-1)
$oHTTP.SetRequestHeader("Referer",'http://'&$host&'/')
$oHTTP.setTimeouts(5000, 5000, 15000, 15000)
$oHTTP.Send("")
If @error Then Exit
ConsoleWrite("-=-=-= Request "&$num&" =-=-=-"&@CRLF)
ConsoleWrite($oHTTP.Status & " " & $oHTTP.StatusText&@CRLF)
Return $oHTTP
EndFunc
Func StringFindSE($string,$start,$end,$start_occ=1,$end_occ=1,$cas=0)
Local $st_count,$source_start,$source_count,$source
$st_count = StringSplit($start,"")
$source_start = StringInStr($string,$start,$cas,$start_occ) + $st_count[0]
$source_count = StringInStr($string,$end,$cas,$end_occ,$source_start) - $source_start
$source = StringMid ($string,$source_start,$source_count)
Return $source
EndFunc
Система пока примитивная очень, даже многопоточностью назвать сложно, в общем алгоритм такой:
1. Проверяется размер файла, делиться на куски по 10 000 байт.
2. Разбивается на группы по 5 кусков.
3. Отправляется 5 запросов на закачку первых 5-ти частей.
4. Дожидается пока будут закачаны все первые 5 частей, по очереди каждую часть.
5. Записывает части по мере загрузки в файл.
6. Отсылает 5 запросов на закачку следующих 5-ти частей.
7. Дожидается пока будут закачаны эти 5 частей.
....(и т.д. по циклу)
N. Закрывает файл
Вот такой скромный алгоритм... Если есть интерес у окружающих - буду выкладывать по мере дорабатываемости... Если интереса нету - значит не судьба

ЗЫ: курсивом выделил то, над чем собираюсь работать =)
ДОПОЛНЕНИЕ: Было выявлено, что данный код не рабочий. (подробнее в сообщениях 6 и 7)
И так, раз мы многопоточности так и не добились - то пока что предлагаю подумать о докачке... А точнее сказать я о ней уже подумал ;)
Вот вам пример докачивающего скрипта, при запуске указываете прямую ссылку на файл - начинается простая загрузка (обычным InetGet).
Если прервать работу скрипта (например Ctrl+Break в SciTE) и запустить скрипт заново, указав ту же ссылку и тот же файл (не докачанный) то выскочит мес-бокс, с вопросом "Докачать?", жмете да и файл докачивается (подробнее в комменте скрипта).
Код:
;~ Докачка осуществляеться по-пакетно, т.е. по частям,
;~ для того чтобы в промежутке между частями выводить
;~ процент закачки и количество скачанных байт.
;~ Если значение $pack установить равное нулю - то докачка
;~ будет происходить одним пакетом, скачиваемый файл будет
;~ харниться в паняти до завершения закачки, после чего будет
;~ сохранен на диск.
;~ Выставлять значение равное нулю не рекомендуеться,
;~ т.к. при закачке боьших файлов будет забиваться память,
;~ а при обрыве придется докачивать заново с того же места,
;~ с которого начинали докачивать ранее.
;~ Но и слишком маленький объем пакета ставить тоже не рекомендуется,
;~ т.к. на запрос части файла тоже тратиться время и трафик.
;~ Чем больше запросов - тем больше трафика сожранного в пустую
;~ и больше затраченного времени...
;~ Самый опимальный (по моему мнению) пакет - 50 Кб (51 200 байт).
Global $pack = 51200 ;Это пакет при докачке (в байтах)
While 1
Global $link = InputBox("Insert link",'Вставьте сюда ссылку на файл','')
Global $fSize = InetGetSize ($link)
Global $filename = StringFindSE($link,'/','',-1,-1)
Global $filetype = StringFindSE($filename,'.','',-1,-1)
If $fSize > 0 Then
ExitLoop
EndIf
MsgBox (16,'Error','Файл не найден.')
WEnd
Global $file_path = FileSaveDialog ("Куда сохранять?", "::{20D04FE0-3AEA-1069-A2D8-08002B30309D}", "(*."&$filetype&")",0,$filename)
Global $filenameN = StringFindSE($file_path,'\','',-1,-1)
If FileExists ($file_path) And FileGetSize($file_path) > 0 Then
$do = MsgBox (35,"Докачать?","Докачать файл?"&@CRLF&@CRLF&"Если нажать ''Нет'', то файл будет заменен.")
If $do = 2 Then
Exit
ElseIf $do = 6 Then
Global $file = FileOpen ($file_path,9)
$ffSize = FileGetSize($file_path)
_resume($ffSize)
ElseIf $do = 7 Then
FileDelete ($file_path)
_download ()
EndIf
ElseIf Not FileExists ($file_path) Then
_download()
Else
FileDelete ($file_path)
_download ()
EndIf
MsgBox (0,'Готово',"Файл "&$filenameN&" закачан!")
Exit
Func _download()
$download = InetGet($link,$file_path,1,1)
ProgressOn("Закачка файла "&$filenameN, "Файл "&$filenameN&" закачивается...", "0 Кб из "&Round($fSize/1024)&" Кб")
While InetGetInfo($download,2) = False
$aData = InetGetInfo($download,0)
ProgressSet(Round($aData/$fSize*100), "Файл "&$filenameN&" закачивается... "&Round($aData/$fSize*100)&"%", Round($aData/1024)&" Кб из "&Round($fSize/1024)&" Кб")
Sleep(250)
Wend
ProgressOff ()
InetClose ($download)
EndFunc
Func _resume($StartByte)
$i = 1
If $pack > 0 Then
ProgressOn("Закачка файла "&$filenameN, "Файл "&$filenameN&" закачивается..."&Round($ffSize/$fSize*100)&"%", Round($ffSize/1024)&" Кб из "&Round($fSize/1024)&" Кб")
For $StartByte = $StartByte To $fSize Step $pack
ConsoleWrite(@CRLF&"Запрос №"&$i&@CRLF&"Стартовый байт запроса = "&$StartByte&@CRLF&"Конечный байт запроса = "&$StartByte+$pack-1&@CRLF&"Всего байт в файле = "&$fSize&@CRLF)
_request($StartByte,$StartByte+$pack-1)
ProgressSet(Round(($StartByte+$pack-1)/$fSize*100), "Файл "&$filenameN&" закачивается... "&Round(($StartByte+$pack-1)/$fSize*100)&"%", Round(($StartByte+$pack-1)/1024)&" Кб из "&Round($fSize/1024)&" Кб")
$i += 1
Next
ProgressOff()
Else
TrayTip ("Внимание","Файл закачиваеться в фоновом режиме, ни каких уведомлений о состояянии загрузки не будет выводиться до завершения загрузки.",5000,1)
_request($StartByte,'')
EndIf
EndFunc
Func _request($SB,$EB)
$host = StringFindSE ($link,'http://','/',1,1)
$oHTTP = ObjCreate("WinHttp.WinHttpRequest.5.1")
$oHTTP.Open("GET", $link)
$oHTTP.SetRequestHeader("Host",$host)
$oHTTP.SetRequestHeader("Accept", "*/*")
$oHTTP.SetRequestHeader("User-Agent", "Downloader/1.0 (compatible)")
$oHTTP.SetRequestHeader("Range", "bytes="&$SB&"-"&$EB)
$oHTTP.SetRequestHeader("Referer",'http://'&$host&'/')
$oHTTP.setTimeouts(5000, 5000, 15000, 15000)
$oHTTP.Send("")
ConsoleWrite($oHTTP.Status & "/" & $oHTTP.StatusText&@CRLF)
$oHTTP.WaitForResponse
FileWrite ($file,$oHTTP.ResponseBody)
EndFunc
Func StringFindSE($string,$start,$end,$start_occ=1,$end_occ=1,$cas=0)
Local $st_count,$source_start,$source_count,$source
$st_count = StringSplit($start,"")
$source_start = StringInStr($string,$start,$cas,$start_occ) + $st_count[0]
$source_count = StringInStr($string,$end,$cas,$end_occ,$source_start) - $source_start
$source = StringMid ($string,$source_start,$source_count)
Return $source
EndFunc