NetSock (sockety) i pobranie pliku z serwera za pomocą GET

0

Witam. używam biblioteki NetSock (https://github.com/gynvael/NetSock) i naklepałem taki swój kodzik (pomijam otwieranie tego samego pliku 3 razy, poki co ma tylko działać). No i plik jest pobierany, jednak gdy chce pobrać plik drugi raz to już jakby nie otrzymuje żadnych danych. A jeżeli rozłącze socketa i podłącze ponownie i pobiore ten drugi plik (który nie chciał się pobrać) to pobierze go elegancko.

Kod: (wrzucam tylko main.cpp bo reszta to ta bilbioteka NetSock)
https://pastebin.com/pVDaQT9t

0

Jeśli Windows, to dlaczego nie WinHTTP lub nawet libcurl?

0

A chciałem tak na sockety spojrzeć. Pewnie użyje czegoś co wymieniłeś, jednak nurtuje mnie problem w moim kodzie

0

@Rivit Nie wysyłasz Keep-Alive więc HTTP serwer zamyka socketa po swojej stronie jak już wszystko wyśle za pierwszym razem.

(edit literówki, dużo literówek)

0

Jak to się robi, mam to w GET napisać tak Connection: keep-alive czy cos takiego?

Popróbuje i dam znać

0
std::ostringstream oss;

oss << "GET " << file << " HTTP/1.0\r\n"
	<< "Connection: keep-alive\r\n\r\n";

...

std::string s = oss.str();

f (send(socket_desc, s.c_str(), s.size(), 0) < 0) { ... }
0

kurcze dalej coś nie pobiera. pierwszy plik jest a drugi juz nie

0

To "nie pobiera" to trochę za mało. Nie sądzisz? Użyj debugera albo przynajmniej określ, w którym miejscu jest problem, czy przy send, czy recv.

BTW, dlaczego używasz send czy recv zamiast metod klasy NetSock? Zresztą cały ten kod to takie C z klasami.

0

no przy recv sie wykłada. pokazuje ze dlugosc pobranych to zero. jakby odrzucał połączenie czy coś w tym stylu. Bo plik się pusty stworzy czyli send się udaje

Używam tego, później ograne i uzyje bez tej bilbioteki.

0

Ciężko powiedzieć, co może być problemem. Może ciasteczka z poprzedniego zapytania powinny być dodane go nagłówka GET...

0

HTTP/1.1 200 OK
Date: Wed, 06 Jun 2018 1141 GMT
Server: Apache/2.4.29 (Unix)
Last-Modified: Fri, 16 Mar 2018 2035 GMT
Content-Length: 280
Accept-Ranges: bytes
Age: 2333
Keep-Alive: timeout=10, max=1000
Connection: Keep-Alive

To dostaje po pierwszym requeście. Tu chyba wszystko okej, Jednak nie wiem już co może być nie tak :/

1

@Rivit
Hmm, a spróbuj zmienić HTTP/1.0 na HTTP/1.1 w 36 linii i dodać obowiązkowy nagłówek "Host: cdimage.debian.org" w pakiecie.

A btw, jeśli korzystasz z NetSocka (moja współczucia btw), to tam są funkcje typu Read/Write - nie trzeba ręcznie wywoływać send/recv.

0

oss << "GET " << file << " HTTP/1.1\r\nHost: cdimage.debian.org\r\n" << "Connection: keep-alive\r\n\r\n";

Pomimo tego nadal pobiera pierwszy, a drugi nie dostaje w ogóle odpowiedzi :/
Nadal dostaje to:

title

Tak, wiem, że są tam te funckje, jednak póki co ogarnę to, a potem przerzucę się ;)
Ewentualnie czy ktoś mógłby pokazać mi jak użyć tych funkcji z tej biblioteki? Nie wiem czy mam użyć Read czy ReadAll i czy to sie samo przerwie jak nie bedzie juz danych do pobrania czy jak? :x

1

Przeanalizowałem ten twój kod jeszcze raz i wydaje mi się, że problem leży w pętli z recv. Chodzi o to, że próbujesz na jednym połączeniu odbierać odpowiedzi na dwa zapytania, a odbierasz jedną odpowiedź do oporu, aż recv zwróci 0 lub błąd. To działa tylko w układzie jedno połączenie -> jedno zapytanie. Jeśli chcesz czytać na jednym połączeniu kilka odpowiedzi, powinieneś odebrać wpierw nagłówek, wydobyć z niego długość pliku z pola Content-Length i dokładnie tyle bajtów przeczytać z socketa. Dziwne, że od razu tego nie zauważyłem...

0

Hmmm, troche rozumiem.
Jednak, jak najpierw pobrać sam nagłówek, a dopiero potem dane?

Edit. Przez HEAD da rade chyba tylko potem jak pobrać same dane :/

1

A masz:

class socket_buffer:public std::streambuf
{
public:
	int underflow() 
	{
		int bytes_read = socket.Read(buffer, sizeof(buffer));
		if(bytes_read <= 0) return EOF;
		setg(buffer, buffer, buffer + bytes_read);
		return *buffer;
	}
	
	socket_buffer(NetSock &socket_) 
		:socket(socket_)
	{
		underflow();
	}

private:
	NetSock &socket;
	char buffer[2048];
};
bool downloadFile(NetSock &n, const string &file, const string &where)
{
	std::ostringstream oss;

	oss << "GET " << file << " HTTP/1.1\r\n"
		<< "Host: " << "cdimage.debian.org" << "\r\n"
		<< "Connection: Keep-Alive\r\n"
		<< "\r\n";

	std::string s = oss.str();

	if(n.WriteAll(s.c_str(), s.size()) <= 0) return false;

	socket_buffer sbuf(n);
	std::istream is(&sbuf);

	int total_data_len = -1;

	while(std::getline(is, s) && s.size() > 1)
	{
		std::istringstream iss(s);
		std::string name;

		std::getline(iss, name, ':');
		if(name == "Content-Length")
			iss >> total_data_len;
	} 
		
	if(total_data_len == -1)return false;

	std::ofstream ofs(where, std::ios::binary);

	char buff[1024];

	while(total_data_len > 0 && is.read(buff, std::min(1024, total_data_len)))
	{
		ofs.write(buff, is.gcount());
		total_data_len -= is.gcount();
	}
	return total_data_len == 0;
}

Funkcja jest niechlujnie napisana i nie wiem, czy zadziała na kontencie binarnym, ale dla tych plików działa :)

PS. nie chciało mi się kombinować, żeby istream na moim bufforze konwertował \r\n na \n, dlatego czytane linie będą zawierać \r na końcu.

0

Mógłbyś to chociaż troche wyjaśnić? chociaż cześć związaną z tą klasą socket_buff?

0

socket_buffer to klasa, która dostarcza dane z socketa strumieniowi istream. Odsyłam do dokumentacji std::streambuf. W pętli z getline funkcja czyta kolejne linie odpowiedzi i szuka tej z długością pliku. Pętla czyta do końca nagłówka (pusta linia). Reszty tłumaczyć chyba nie trzeba :)

0

Super! Dzięki.

main.cpp: In function 'bool downloadFile(NetSock&, const string&, const string&)':
main.cpp23: error: variable 'std::ofstream ofs' has initializer but incomplete type
std::ofstream ofs(where, std::binary);

Tu mu coś nie pasuje jeszcze

Ok, dzięki wielkie ;)

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