-
Добрый день. Ситуация такая: скачиваю файл по http вот так:
function download (ServerName,File: string):boolean;
var
s: TSocket;
Data: TWSAData;
Addr: TSockAddr;
Recived: Integer;
BtBuff: array [0..1023] of Byte;
HTTPRequest: string;
F: File;
begin
WSAStartup($101, data);
s:=socket(AF_INET, SOCK_STREAM,IPPROTO_TCP);
Addr.sin_family:=AF_Inet;
Addr.sin_port:=htons(80);
Addr.sin_addr.S_addr:=inet_addr(PAnsiChar(ServerName));
if (connect(s,Addr,SizeOf(TSockAddr)) <> SOCKET_ERROR) then
begin
HTTPRequest:='GET '+File+' HTTP/1.1'+#13#10+'Host: '+ServerName+#13#10+'Connection: Close'+#13#10#13#10;
send(s, HTTPRequest[1], length(HTTPRequest),0);
Recived:= 1;
AssignFile(F,File);
Rewrite(F, 1);
while Recived <> 0 do
begin
Recived:= recv(s,BtBuff,Length(BtBuff),0);
BlockWrite(F,BtBuff,Recived);
end;
CloseFile(F);
closesocket(s);
Result:= True;
end;
WSACleanup();
end;
Но проблема в том, что если открыть скачанный файл в текстовом редакторе, то в начале есть: HTTP/1.1 200 OK
Date: Sat, 12 Apr 2008 16:42:10 GMT
Server: Apache/2.2.6 (Win32) PHP/5.2.3
Last-Modified: Sat, 12 Apr 2008 16:12:24 GMT
ETag: "32fe-1f0-50f3172c"
Accept-Ranges: bytes
Content-Length: 496
Connection: close
Content-Type: application/zip Вопросы: 1. Как вы думаете, как лучше удалять этот заголовок? 2. И вообще, как посоветуете обеспечивать "одинаковость" файла с оригиналом на сервере? Просто у меня есть подозрение, что даже если я уберу этот заголовок, и получу ЧекСуммы файлов с сервера и скачанного, они будут разные. Как думаете? Спасибо
-
> 1. Как вы думаете, как лучше удалять этот заголовок?
после заголовка два раза перевод строки: #13#10#13#10
> Как думаете?
Все будет ок.
-
Спасибо.
-
Еще раз здравствуйте. К сожалению, не могу похвастаться, что все получилось... Скорее получилось именно то, чего я боялся. Файл скачивается неправильно :( HTTPRequest:='GET '+PathToFile+' HTTP/1.1'+#13#10+'Host: '+ServerName+#13#10+'Connection: Close'+#13#10#13#10;
send(s, HTTPRequest[1], Length(HTTPRequest),0);
Flag:= 0;
Recived:= 1;
while Recived <> 0 do
begin
Recived:= recv(s,BtBuff,Length(BtBuff), 0);
if Flag = 0 then
begin
for i:=0 to Length(BtBuff)-1 do
if ((BtBuff[i] = 13) AND (BtBuff[i+1] = 10)) then
if ((BtBuff[i+2] = 13) AND (BtBuff[i+3] = 10)) then
break;
ii:= i + 4;
for i:= ii to Length(BtBuff)-1 do
begin
SetLength(BtBuffTmp,Flag+1);
BtBuffTmp[Flag]:= BtBuff[i];
inc(Flag);
end;
BlockWrite(F,BtBuffTmp,Length(BtBuffTmp));
Flag:= 1;
end
else
BlockWrite(F,BtBuff,Recived);
end;
CloseFile(F);
closesocket(s); Суть в следующем: 1. Начинаем скачивать файл. 2. Так как заголовок http попадет только в 1й массив байт, то для 1го прохода один вариант обработка, а для второго и других - просто пишем в файл. 3. 1й проход обрабатываю так: 3.1 ищу в массиве 13101310 и запоминаю номер следующего элемента. 3.2 начиная с номера запомненного элемента пишу в новый массив 3.3 пишу новый массив в файл Не работает :'(
-
какой ужас
-
Да, к сожалению ужас. Я не просто так выложил данный пост. Дебажить н-ный раз скачивание файла побайтно это не просто так :(
Я думал какой-нибудь профессиональный программист только окинув взглядом данный код увидит проблему... Ведь когда уже решал аналогичную задачу, все как на ладони...
Может и нет.
-
> Dima
Твой код никуда не годится. Если он каким-то чудом и будет где то работать, так это в стерильных условиях локальной сети. Да и то неправильно будет работать.
Объяснять долго почему. Не работают так с HTTP сервером. Ну хотя бы потому, что он заголовок в ответе не просто так сообщает, а для информации и дальнейшего использования.
-
> Dima
Лучше возьми TIdHTTP или хотя бы WinInet Api используй. Зачем сразу в WinSock полез?
-
Странно если бы получилось. То что после заголовка это далеко не файл, а то что указано в заголовке, который ты благополучно уничтожаешь. То что остается требуется еще обрабатывать в соответствии с заголовком. Как сказали не мучайся, пользуйся готовым компонентом.
-
> Лучше возьми TIdHTTP или хотя бы WinInet Api используй. > Зачем сразу в WinSock полез?
Да дело том, что я и переделываю програму с WinInet. В проге с WinInet все было шикарно и все "работало", но программа висла. Я вызывал URLDownloadToFile и все. Программа висит намертво...
Читал про это в Интернете, говорят что это глюк в WinInet... Поэтому я отказался от WinInet..
Я понял, что это все не так просто, поэтому может тогда посоветуете грамотную литературу на эту тему? Только не говорите искать в гугле, там я поищу тоже)))
-
А ты 13101310 отличаеш от #13#10#13#10! Анализируй в ответе от сервера строку статус и длину передаваемых байт после заголовка, т.е. HTTP/1.* 200 OK ... Content-Length: ???
200 или 2xx - все нормально! Content-Length: <длина файла после заголовка>
-
> FireMan_Alexey (19.04.2008 17:12:10) [10]
30x тоже нормально, например 302 File Moved - переадресация в другое место.
-
-
> Content-Length: <длина файла после заголовка>
может этого заголовка и не быть. А Content-Type может быть multipart/x-mixed-replace и тогда будут приходить порции с разделителями и у каждой порции будет подзаголовок с Content-Length порции. Вообще говоря вариаций много и писать все самому с нуля это надо весь RFC читать.
-
Dima (19.04.08 16:55) [9] В проге с WinInet все было шикарно и все "работало", но программа висла. против "висла" можно прикрутить отдельный поток (Thread)... если ты реализуешь полную поддержку RFC у тебя "виснуть" будет чаще и серьезнее :)
-
Да у него в приеме нет анализа ошибки после recv поэтому сложно что-либо сказать, что он там получает! Читай про winsock и статусы ошибок при приеме/передаче.
|