[c] socket pobieranie kanałów RSS

0

Potrzebuję napisać program który będzie pobierał kanał RSS z podanego adresu.
Korzystam z przykładu z tutoriala o socketach ze strony firsthost
Kod wygląda tak:

#include <stdio.h>
#include <winsock2.h>

int resolveHost( char *host )
{
	LPHOSTENT hostEntry = gethostbyname(host);

	if ( !hostEntry )
	{
		unsigned int addr = inet_addr( host );
		hostEntry = gethostbyaddr((char *)&addr, 4, AF_INET);

		if ( !hostEntry )
		{
			return 0;
		}
	}

	return *((int*)*hostEntry->h_addr_list);
}

int main(int argc, char* argv[])
{
	WSADATA		wsaData;
	SOCKADDR_IN saddr;
	SOCKET		sock;
	char		*http_req = "GET http://www.tvn24.pl/sport.xml HTTP/1.0\n\n";
	char		index[1024*20] = { 0 };

	WSAStartup( MAKEWORD(2,2), &wsaData );

	sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);

	saddr.sin_addr.S_un.S_addr = resolveHost ("www.tvn24.pl");
	saddr.sin_family = AF_INET;
	saddr.sin_port = htons(80);

	if ( connect(sock, (SOCKADDR*)&saddr, sizeof(SOCKADDR)) == SOCKET_ERROR )
	{
		/* połączenie się nie powiodło */
		sock = 0;
		return -1;
	}

	send(sock,http_req,strlen(http_req),0);
	recv(sock,index,1024*20,0);

	printf("%s", index);;

	closesocket(sock);
	WSACleanup();
	return 0;
}

Niestety działa tylko w niektórych przypadkach, a mianowicie wtedy gdy adres do kanału jest podany w odniesieniu do domeny głównej (nie przez subdomenę [np. http://sport.wp.pl/kat,1726,rss.xml]).

Czy wie ktoś co powinienem zrobić, aby program nie tylko potrafił pobierać kanały gdy dostanie adres do domeny głównej?

Przy jednej z prób otrzymałem taki wynik:
Location: http://http/index.php/pl/www.XXXXX.pl/index.php/pl
Gdy zmienne były ustawione tak:

char		*http_req = "GET http://www.XXXXX.pl/index.php/pl HTTP/1.0\n\n";
saddr.sin_addr.S_un.S_addr = resolveHost ("www.XXXXX.pl");
0

Dostajesz przekierowanie na innego hosta -> 303. Czyli jeśli dostaniesz od serwera odpowiedź o tym numerze, musisz wyłuskać wartość pola location, który jest url-em, i całą procedurę powtórzyć.

p.s. pod windowsem możesz użyć funkcji biblioteki //wininet//. Ich użycie uwolni Cię od zabawy z przetwarzaniem nagłówków, przekierowań etc.

0

W większości przypadków gdy próbuję pobrać stronę otrzymuję taką odpowiedź:

UNKNOWN 400 Bad Request
Server: aris
Content-Type: text/html
Date: Sun, 20 May 2012 12:56:48 GMT
Last-Modified: Sun, 20 May 2012 12:56:48 GMT
Accept-Ranges: bytes
Connection: close

<HTML><HEAD><TITLE>400 Bad Request</TITLE></HEAD>
<BODY><H2>400 Bad Request</H2>
Your request has bad syntax or is inherently impossible to satisfy.
<HR>
<ADDRESS><A HREF="http://www.wp.pl/">aris</A></ADDRESS>
</BODY></HTML>

Zmienne wyglądają wtedy tak:

char		*http_req = "GET http://media.wp.pl/rss.xml HTTP/1.0\n\n";
saddr.sin_addr.S_un.S_addr = resolveHost ("media.wp.pl");
0
char *http_req = "GET /rss.xml HTTP/1.1\r\nHost: media.wp.pl\r\n\r\n";

W HTTP koniec linii to sekwencja \r\n a nie \n.

0
0x666 napisał(a):
char *http_req = "GET /rss.xml HTTP/1.1\r\nHost: media.wp.pl\r\n\r\n";

W HTTP koniec linii to sekwencja \r\n a nie \n.

Zmieniłem na to co podałeś o od serwera otrzymuję takie coś:

HTTP/1.1 200 OK
Server: aris
Content-Type: text/xml; charset=ISO-8859-2
Pragma: no-cache
Set-Cookie: statid=89.72.161.154.4190:1337526707:1050699485:v1; path=/; expires=
Wed, 20-May-15 15:11:47 GMT
Set-Cookie: statid=89.72.161.154.4190:1337526707:1050699485:v1; domain=.wp.pl; p
ath=/; expires=Wed, 20-May-15 15:11:47 GMT
Content-Length: 8665
Connection: close

Czyli chyba że źle jest odczytywany adres który chcę wyświetlić. (w domain jest .wp.pl, a powinno być media.wp.pl)
Adres serwera dalej zostawiłem ten sam:

saddr.sin_addr.S_un.S_addr = resolveHost ("media.wp.pl");
0

Przecież to jest nagłówek odpowiedzi! Kod 200 oznacza, że wszystko ok, serwer odesłał ci 8665 bajtów danych (pomijając nagłówek). Dane znajdują się za nagłówkiem, czyli

...
ath=/; expires=Wed, 20-May-15 15:11:47 GMT
Content-Length: 8665
Connection: close

< 8665 bajtów danych >

pusta linia oznacza koniec nagłówka.

Poczytaj trochę o HTTP, bo widzę, że Twoja wiedza o tym protokole jest żadna.

0
0x666 napisał(a):

Przecież to jest nagłówek odpowiedzi! Kod 200 oznacza, że wszystko ok, serwer odesłał ci 8665 bajtów danych (pomijając nagłówek). Dane znajdują się za nagłówkiem, czyli

...
ath=/; expires=Wed, 20-May-15 15:11:47 GMT
Content-Length: 8665
Connection: close

< 8665 bajtów danych >

pusta linia oznacza koniec nagłówka.

Poczytaj trochę o HTTP, bo widzę, że Twoja wiedza o tym protokole jest żadna.

Dobrze widzisz, ale niestety nie mam w tej chwili czasu na naukę HTTP [co nie oznacza, że nie chcę tego się nauczyć](mam nadzieję, że aby pobrać zawartość strony nie będzie potrzebna zbyt rozległa wiedza na ten temat). Program muszę napisać na określony czas i niestety nie zostało go za dużo.

W programie mam stworzoną zmienną do której zapisuję to co zwróci serwer. Później wyświetlam to na ekran to co się tam zapisało. W zmiennej na pewno jest miejsce, aby pomieścić te 9000 bajtów (nawet dużo więcej), a mimo wszystko zapisuje się tam jedynie to co widać w poprzednim poście. Co jest nie tak?
Ważną uwagą, jest, że sprawdziłem to co mi wysłałeś na innej stronie i tam otrzymuję normalnie zawartość strony.

Również mam pytania które będą ważne gdy już będzie działało pobieranie stron bez problemu.

  1. Czy istnieje możliwość, aby pobrać z serwera jedynie samą liczbę (int) bajtów które zawiera dana strona? Dzięki temu można by stworzyć dynamiczną rezerwację pamięci bez jej marnowania lub bez zagrożenia, że coś się nie zapisze?
  2. Czy jest możliwość, aby zapisać zawartość strony bezpośrednio do pliku, bez zapisywania jej do zamiennej a później dopiero do pliku?
0

Co jest nie tak?

No np. to, że recv nie musi odebrać od razu całości odpowiedzi.

Co do pytań:

  1. w pewnym sensie tak, w nagłówku masz pole Content-Length, ono mówi o wielkości danych. Problem w tym, że to pole nie musi występować, wtedy czytasz z socketa, aż recv zwróci 0 (wtedy pole Connection jest ustawione na close).
  2. oczywiście, że tak. Możesz czytać z socketa fragmentami (np. po 1KB) i to, co przeczytasz, od razu zapisujesz do pliku.
0

Jednak się nie obędzie bez nauki

Znasz może jakąś stronę czy książkę, może wystarczy jakiś rozdział w książce gdzie dobrze są opisane sockety? Do tej pory korzystałem z tutoriala na stronie firsthost.nazwa.pl

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