Kirjautuminen

Haku

Tehtävät

Keskustelu: Ohjelmointikysymykset: C: HTTP GET ja sivun tallentaminen tiedostoon

MagFed [27.01.2007 17:56:46]

#

Ohjelmani avaa HTTP-yhteyden ja lähettää GET-pyynnön palvelimelle. Tallennan saapuvan sivun tiedostoon while-loopissa. Jos laitan bufferin kooksi esim. 512 tai 1024, tallentuneeseen tiedostoon tallentuu teksti "GET /xyz/index.html Host: www.esimerkkisivu.fi" useaan eri kohtaan keskelle tallennettua tiedostoa. Kyseessä on siis sama GET-pyyntö, jonka lähetän palvelimelle. Tekstinpätkä toistuu tiedostossa useasti.

lainaus:

...
<TD ALIGN="CENTER">
<GET /xyz/index.html
Host: www.esimerkkisivu.fi

TABLE CELLSPACING="0" CELLPADDING="10" BORDER="0">
...

Empiiristen kokeiden mukaan bufferin ollessa 2048 tai suurempi tiedostoon tallentuu vain pelkkä pyydetty nettisivu. Onko kellään näkemystä miksi asia on näin? Onko koodissani joku ratkaisevanlaatuinen virhe, vai mistäkö moinen johtuu? Alla vielä koodi sivun tallentamiseen.

    sprintf(msg, "GET /xyz/index.hmtl \n Host: www.esimerkkisivu.fi \n\n");
	len = strlen(msg);
	msg[len+1]='\0';

    ...

	temp = send(sock, msg, len, 0);

	while(temp != 0) {
		if ((temp = recv(sock, buffer, sizeof(buffer), 0)) == -1)
            perror("recv");
		fprintf(tiedosto, "%s", buffer); /* write buffer to file */
		memset(buffer,'\0',sizeof(buffer)); /* empty the buffer */
	}

Niin ja tuo nettisivun osoite on vain esimerkki, oikeasti yritän tallentaa omaa nettisivuani, jonka osoitetta en halua julkisuuteen. :)

Metabolix [27.01.2007 19:44:55]

#

Uskaltaisin väittää, että kun pyydät bufferin täyteen tietoa, sen lopusta jää puuttumaan nollamerkki, jolloin myös muistissa sen jälkeen tuleva asia kirjoitetaan tiedostoon (ja siinä sattuu ilmeisesti olemaan juuri tuo mainitsemasi). Oikea ratkaisu tähän olisi siis kirjoittaa tiedostoon fwrite-funktiolla sen verran, kuin on saatu luettua:

if (send(sock, msg, len, 0) == -1) {
    perror("send\n");
} else {
    // Kun dataa riittää, kirjoitetaan tiedostoon ja luetaan lisää
    while ((temp = recv(sock, buffer, sizeof(buffer), 0)) > 0) {
        fwrite(buffer, 1, temp, tiedosto);
    }
    if (temp) { // == -1, koska positiivisella ei pääse tänne ja muuta negatiivista ei kai tule
        perror("recv: virhe\n");
    } else { // == 0
        printf("recv: yhteys suljettu tai data loppui\n");
    }
}

feenix [29.01.2007 08:51:42]

#

Ja vielä muutamia vinkejä:

- HTTP-speksi vaatii CRLF joten älä lähetä pelkkää \n:ää.

- Otsakkeiden aloittaminen välilyönnillä on väärin, koska se voidaan tulkita edellisen otsakkeen jatkoarvoksi eikä omaksi otsakkeekseen.

- Protokollaversion lähettäminen on ihan nättiä, vaikkei olekaan aivan vaadittua vanhemmissa versioissa. (1.1:n käyttäminen ei ole välttämätöntä, varsinkin jos haluaa olla varma ettei yhteyttä jätetä auki seuraavia pyyntöjä varten, 1.0 on parempi tässä). Toisaalta 1.0:n kanssa host-otsaketta ei välttämättä ehkä tarvitsisi käsitellä. En kylläkään tiedä yhtään tapausta jossa ei käsiteltäisi.

Eli oikeammin:

"GET /xyz/index.hmtl HTTP/1.0\r\nHost: www.esimerkkisivu.fi\r\n\r\n"

tai

"GET /xyz/index.hmtl HTTP/1.1\r\nHost: www.esimerkkisivu.fi\r\nConnection: close\r\n\r\n"


(Ja kyllä, osa servereistä ei hyväksy pyyntöä jos ei tule CRLF, empiirisestikin havaittu)

MagFed [08.02.2007 01:31:51]

#

Mikä olisi muuten helpoin tapa olla tallentamatta HTTP-otsaketta? Eli jos hakeekin GETillä tekstitiedoston sijaan vaikka gif-kuvan, jolloin ei halua tiedoston alkuun mitään ylimääräistä.

Onko helpompaa/nopeampaa filtteröidä headeri pois jo silloin, kun tiedostoa kirjoitetaan, vai käydä ronkkimassa valmiin tiedoston alusta pois header-lauseet?

FooBat [10.02.2007 15:49:18]

#

Joudut puskuroimaan luettua dataa hiukan muistiin ennen sen tallentamista, etsimään siitä ensimmäisiä peräkkäisiä rivinvaihtoja ja tallentaa vasta niiden jälkeen tuleva osa tiedostoon.

Vastaus

Aihe on jo aika vanha, joten et voi enää vastata siihen.

Tietoa sivustosta