Ściąganie pliku [2x FAQ]

0

Witam!

Nigdy nie sądziłem, że będę zmuszony zadać pytanie w takiej sprawie :-8.

Potrzebuję zassać jeden plik z internetu.
W FAQ znalazłem dwa różne przykłady dla Delphi:
http://4programmers.net/view_faq.html?id=8
http://4programmers.net/view_faq.html?id=463

Niestety - w obu przypadkach otrzymuję błąd kompilatora:

Unresolved external symbol referenced from module.

Czy jest jakaś prosta i skuteczna metoda do ściągnięcia wskazanego pliku?

I proszę nie pisać mi, abym zainstalował jakieś pakiety Indy. Jest bezsensem instalowanie zestawu nastu komponentów w celu realizacji tak prostej (mogłoby się wydawać) rzeczy.

0

Najpewniej masz w BCB (o niego ci chodzi?) komponent TClientSocket - zalęznie od tego czego potrzebujesz wykorzystaj protokół HTTP, bądź FTP (na sici jest dużo opisów - szczególnie po angielsku)

(przez HTTP 0.9 najprościej - nie ma autoryzacji (jak w FTP) ani dodatkowych [a niepotrzebnych ci] informacji (jak w HTTP 1.1) - wystarczy GET)

0

Hmm - coś nie teges :-8

Przeszukałem wszystkie posty zawierające "ClientSocket" i znalazłem tylko jeden interesujący:
http://4programmers.net/Forum/viewpost.html?id=37961&h=ClientSocket

Jednak ten kod w momencie

ClientSocket1->Active = true;

wywala mi: "Windows socket error: (11001), on API 'ASync Lookup"

Gdybym tylko znał się na sieci tak jak znam się na dzierganiu sweterków to może ten błąd by mi coś powiedział - a tak jest to tylko kolejny niedziałający kod z tej strony... :|

Poza tym do jego działania potrzebna jest znajomość jakiś totalnie nieznanych mi komend jak GET :-8

[<font color="blue">dopisane</span>]
Hmm - zmieniłem ClietnType na "ctBlocking" i teraz zamiast "ASync Lookup" mam "connect".

0

Witam
Wyjątek wyskakuje gdy nie może się połączyć tzn. jeżeli nic nie odbiera połączenia może zły IP lub host ?

[do postu poniżej]
Sprawdziłem i masz rację [wstyd] wyciąłem żeby w oczy nie kłuło :-)

0

ClientSocket1->Port = port; //ustawia port na jakim ma się połączyć (np. 80 to WWW/HTTP)

ClientSocket->Host = host; //String zawierający nazwę host lub adres IP na który się łączymy (np. "4programmers.net/Forum")

ClientSocket->Address = address; //ustawia adres IP na który się łączymy (jest chyba dużo szybsz łączenie, niż przy podaniu IP w host)

ClientSocket->Active = true;// łączymy sie!

EVENTY:

ClientSocket->OnConnect(); //event uruchamiany przy połączeniu;

ClientSocket->OnDisconnect(); //przy rozłączeniu

ClientSocket->OnError(); //kiedy pojawi się błąd (np. nie można się połączyć) jeżeli wewnątrz wpiszesz frazę: ErrorCode = NULL; - nie pojawi się komunikat o błędzie

ClientSocket->OnRead(); //kiedy server coś nam nada...

SOCKET:

jest to klasa 'załączana' do powyższych komunikatów:

ClientSocket->
Socket->ReceiveText(); //oddaje nam odebrany od servera string (tylko raz - potem czyści)

Socket->SendText("Coś tam"); //wysyła String do servera

hmm... i myślę, że to ci na pocżatek wystarczy (chyba jest coś na ten temat w Helpie (Services Application) i jest przykład Czata (BCB\Examples)...

[ADD]
Embraced - :)

0

Dzięki za opisy, ale nic to nie pomogło :|.
Na google znalazlem taki przykład:
http://www.scalabium.com/faq/dct0116.htm

Przerobiłem go na BCB i nadal mam błąd "no connect" przy linii

ClientSocket->Open();

Zgłupiałem już :|.

0

Sprawdź:

  1. port MUSI być != 0
  2. MUSI być podany adres (lub host)
0

Krecik - patrzyłeś na ten kod?
No aż taki głupi to ja nie jestem...

A w kodzie wyraźnie stoi:

ClientSocket->Host = strHost;
ClientSocket->Port = 80;

a tę funkcję wywołuję jak następuje:

DownloadFile("4programmers.net", "/templates/subMain/gfx/home.gif", "c:\\home.gif", ClientSocket1);

więc strHost nie jest pusty...

0

:(:( U mnie działa...

Uruchom ponownie system :)

0

Hmm - no dobra - po wielu perturbacjach i wymianie poglądów na IRCu w końcu ściągnąłem plik.
Problemem był "\n" zamiast "\r\n" oraz "http://" w tekście hosta.
Tyle że na początku jest nagłówek :|.
Plik wygląda tak:

HTTP/1.1 200 OK
Date: Tue, 04 Nov 2003 1650 GMT
Server: Apache/1.3.27
Last-Modified: Wed, 09 Jul 2003 1832 GMT
ETag: "8363b-6c33-3f0c5ffc"
Accept-Ranges: bytes
Content-Length: 27699
Content-Type: image/gif

GIF89a........ (tutaj jest już obraz)

Czy jest jakiś prosty sposób, aby pozbyć się tego nagłówka?

0

Prawda, że w procedurze wysyłajęcj masz HTTP /1.1
Host: ...
Accept ...
I takie tam?

Wywal z procedury Downloadu wszystkie linijki oprócz pierwszej...
W każdym razie wysyłany do serva string powinien wyglądać mniej~więcej tak: "GET http://www.onet.pl/kropka.gif\n" i nic poza tym...

PS> nie mogę zobaczyć tego przykładu, mam jakieś problemy z komp.

0

Nie wiem czy to coś pomoże , ale w tym artykule jest bardzo dużo na temat http :
http://www.jmarshall.com/easy/http/

Z tego artu :

The initial line is different for the request than for the response. A request line has three parts, separated by spaces: a method name, the local path of the requested resource, and the version of HTTP being used. A typical request line is:

GET /path/to/file/index.html HTTP/1.0

Notes:

GET is the most common HTTP method; it says "give me this resource". Other methods include POST and HEAD-- more on those later. Method names are always uppercase.
The path is the part of the URL after the host name, also called the request URI (a URI is like a URL, but more general).
The HTTP version always takes the form "HTTP/x.x", uppercase.

oraz dotyczące \r\n :

Initial lines and headers should end in CRLF, though you should gracefully handle lines ending in just LF. (More exactly, CR and LF here mean ASCII values 13 and 10, even though some platforms may use different characters.)

0

Dzięki za zainteresowanie.
A więc tak:

jak wyślę:
<font color="darkblue">"GET " + strRemoteFileName + " HTTP/1.0\r\n\r\n"</span>
to dostaję plik o wielkości 0

jak wyślę:
<font color="darkblue">"GET " + strRemoteFileName + " HTTP/1.1\r\nHost: " + strHost + "\r\n\r\n";</span>
to dostaję dobry plik, ale z nagłówkiem - gdyby gdzieś była podana jego wielkość, to bym go sobie wyciął i nie zawracał Wam głowy.

0

hm.... raczej:
<font color="darkblue">"GET " + strRemoteFileName + "\n"</span>

strRemoteFileName musi zawierać z przodu "http://"

PS> wielkość nagłówka chyba nie jest nigdzie określona - jest zależna od servera...

PS2> w celu testów Start->Uruchom->Telnet i tam wklejaj text z jakiegoś notatnika (po połączeniu) - dobry sposób na szybkie przypmnienie sobie komend, kiedy się nie pamięta protokłu :)

0

Krecik - dzięki za szczere chęci, ale upierasz się przy złym rozwiązaniu.
TrOuBLE podał stronę, na której wyraźnie widać standard przesyłanego komunikatu - Twój do niego nie pasuje.

0

!!NO WŁAŚNIE!!

Mój jest starszy... spróbuj...

TrOuBLE podał ci namairy na protokół HTTP/1.1, a ty chcesz bez nagłówka, więc użyj HTTP/0.9
czyli tego, który ja ci podaję... Nowsze Servery obsługują starszy protokół i nie podają mu nagłówka, ponieważ tamten standard go nie zawierał

0

Proszę - czytaj dokładnie co piszę!!

Twoim sposobem dostaję 0 bajtów!

0
  1. Włączam Telnet...
  2. Pierwsze menu od lewej->Połącz
  3. Host = 4programmers.net/Forum
  4. Port = 80
  5. wpisuję:
    [code]GET http://4programmers.net/Forum/viewtopic.html?id=46027&p=1 [/code] i naciskam enter
  6. W odpowiedzi DOSTAJĘ stronę...

PS> z tego co widzę (PROXY na IE) to w HTTP/1.1 nagłówek kończy się pierwszą pustą linią...

0

Jeszcze raz dzięki chłopaki za pomoc. Zgodnie ze standardem (jak było to wspomniane powyżej) nagłówek kończy się pustą linią. Więc wyciąłem ten fragment.

Dla zainteresowanych - oto zassanie pliku via ClientSocket:

Na formie wrzuć obiekt klasy TClientSocket o nazwie (cóż za oryginalność :-)) ClientSocket1

//---------------------------------------------------------------------------
void __fastcall TfForma::mGoClick(TObject *Sender)
{DownloadFile("4programmers.net", "/templates/subMain/gfx/home.gif", "home.gif", ClientSocket1);
}
//---------------------------------------------------------------------------
void __fastcall TfForma::DownloadFile(AnsiString strHost, AnsiString strRemoteFileName,
 AnsiString strLocalFileName, TClientSocket* ClientSocket)
{int intReturnCode;
 AnsiString s;
 char szBuffer[129];
 TFileStream* FileOut;
 TMemoryStream *strumien;

 if (strRemoteFileName[1] != '/')
  strRemoteFileName = "/" + strRemoteFileName;

 strumien = new TMemoryStream();
 try
 {ClientSocket->Host = strHost;
  ClientSocket->ClientType = ctBlocking;
  ClientSocket->Port = 80;

  try
  {ClientSocket->Open();
   //send query
   s = "GET " + strRemoteFileName + " HTTP/1.1\r\n" +
       "Host: " + strHost + "\r\n\r\n";
   intReturnCode = ClientSocket->Socket->SendBuf(s.c_str(), s.Length());

   if (intReturnCode > 0)
   {
    //receive the answer
    //iterate until no more data
    while (intReturnCode > 0)
    {
     //clear buffer before each iteration
     memset(szBuffer, 0, sizeof(szBuffer));

     //try to receive some data
     intReturnCode = ClientSocket->Socket->ReceiveBuf(szBuffer, sizeof(szBuffer));

     //if received a some data, then add this data to the result string
     if (intReturnCode > 0)
      strumien->Write(szBuffer, intReturnCode);
    }
   }
   else
    Application->MessageBox("No answer from server", "Error", MB_OK | MB_ICONSTOP);

   ClientSocket->Close();
  }
  __except(EXCEPTION_EXECUTE_HANDLER)
  {Application->MessageBox("No connection", "Error", MB_OK | MB_ICONSTOP);
  }
 }
  __finally
  {//tu nastąpi wycięcie nagłówka
   FileOut = new TFileStream(strLocalFileName, fmCreate);
   char znak[4];
   znak[3] = 0;
   bool found = false;
   strumien->Position = 0;
   do
   {strumien->Read(znak, 1);
    if (znak[0] == '\r')
    {strumien->Read(znak, 3);
     if (!strcmp(znak, "\n\r\n"))
      found = true;
     else
      strumien->Position -= 2;
    }
   }while (!found);

   FileOut->CopyFrom(strumien, strumien->Size - strumien->Position);
   delete FileOut;
   delete strumien;
  }
}

1 użytkowników online, w tym zalogowanych: 0, gości: 1