pobieranie pliku socket http c

pobieranie pliku socket http c
KL
  • Rejestracja:około 15 lat
  • Ostatnio:prawie 10 lat
0

Witam,
Próbuje zrozumieć jak pobrać plik dla przykładu exe i zapisać na dysku. Nie zależy mi na gotowej odpowiedzi ale na tym żebym zrozumiał o co chodzi.

Kopiuj
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <winsock.h>


int main(int argc, char *argv[])
{
    
WSADATA wsaData;
//WSAData wsaData; 
if (WSAStartup(MAKEWORD(1, 1), &wsaData) != 0) {
fprintf(stderr, "WSAStartup failed.\n");
exit(1);
}

    int socket_desc;
    struct sockaddr_in server;
    char *message ;
    char *server_reply;
    socket_desc = socket(AF_INET , SOCK_STREAM , 0);       
    server.sin_addr.s_addr = inet_addr("127.0.0.1");
    server.sin_family = AF_INET;
    server.sin_port = htons( 80 );

    connect(socket_desc , (struct sockaddr *)&server , sizeof(server));
    message = "GET /z.exe HTTP/1.0\r\n\r\n";
    send(socket_desc , message , strlen(message) , 0); 
    //Receive a reply from the server
    recv(socket_desc, server_reply , strlen(server_reply) , 0);

    puts("Reply received\n");
    puts(server_reply);
 // do tego momentu było ok jak pobierałem zawartość strony www. Przy pliku coś idzie nie tak. 
FILE * fp;


fp=fopen("z.exe", "wb"); // tu z tego co juz sie dowiedziałem próbuje utworzyć plik binarny i zapisać do niego dane
fwrite(  server_reply, sizeof(char),strlen(server_reply), fp);
fclose(fp);

closesocket(socket_desc);
WSACleanup();
  system("PAUSE");	
  return 0;
}
mad_penguin
mad_penguin
  • Rejestracja:ponad 10 lat
  • Ostatnio:ponad 3 lata
  • Lokalizacja:Rzeszów
1
  1. Nie możesz sobie po prostu utworzyć wskaźnika, a później czegoś zapisywać do wskazywanej do niego pamięci:
Kopiuj
char *server_reply;
recv(socket_desc, server_reply , strlen(server_reply) , 0);

Poczytaj o alokacji pamięci.
2. Nie możesz sprawdzić długości odpowiedzi serwera za pomocą strlen, musisz w recv podać maksymalną ilość danych jaką chcesz pobrać i zapisywać je w jakimś buforze o takim rozmiarze, oraz sprawdzać wartość zwracaną przez recv, bo funkcja może ściągnąć mniej danych niż sobie zażyczyłeś i musisz uruchamiać ją w pętli dopóki wszystkie nie zostaną pobrane.
3. Odpowiedź serwera HTTP zaczyna się nagłówkami, zawartość pliku exe zaczyna się dopiero po pustej linii.
Proponuję wrócić do problemu po porządnym douczeniu się podstaw.

KL
. Nie możesz sobie po prostu utworzyć wskaźnika, a później czegoś zapisywać do wskazywanej do niego pamięci: char *server_reply; recv(socket_desc, server_reply , strlen(server_reply) , 0); W przypadku danych tekstowych jak odczytanie html i wypisanie w konsoli nie było problemu.
mad_penguin
mad_penguin
Nie wiem jak to Ci się udało, może akurat wskaźnik wskazywał na jakiś należący do programu obszar pamięci, ale na pewno ten sposób nie jest poprawny. Musisz albo utworzyć zwykłą tablicę, albo użyć malloc.
KL
  • Rejestracja:około 15 lat
  • Ostatnio:prawie 10 lat
0

Program działa już poprawnie pobiera plik i zapisuje tu akurat na przykładzie totalcomander. Ale mam kilka pytań co do kodu i usprawnień Czy moje rozwiązania są poprawne czy można to rozwiązać lepiej szczególnie chodzi mi o fragmenty z malloc, linijka z recv, deklaracja int max = 1000000; , i moment kiedy licze 10 pustych lini zeby nie zapisywać nagłówków serwera.

Kopiuj
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <winsock.h>

int main(int argc, char *argv[])
{
    
WSADATA wsaData;
//WSAData wsaData; 
if (WSAStartup(MAKEWORD(1, 1), &wsaData) != 0) {
fprintf(stderr, "WSAStartup failed.\n");
exit(1);
}

    int socket_desc;
    struct sockaddr_in server;
    int max = 10000000; // skad mam wiedzieć jaki plik będzie wielki bo to jednak jest jakies ograniczenie
    char *message ;
   
  
    char *server_reply;
    server_reply = (char *) malloc(max * sizeof(char)); // poprawnie użyłem ? mój 1 raz
    
    socket_desc = socket(AF_INET , SOCK_STREAM , 0);       
    server.sin_addr.s_addr = inet_addr("127.0.0.1");
    server.sin_family = AF_INET;
    server.sin_port = htons( 80 );
    /
    connect(socket_desc , (struct sockaddr *)&server , sizeof(server));
   
    message = "GET /tcm851ax64.exe HTTP/1.0 \r\n\r\n"; // z.exe
    send(socket_desc , message , strlen(message) , 0); 
   
    int iResult;

    iResult =   recv(socket_desc, server_reply , max, 0); // skąd mam wiedzieć jak pobrać wartość dynamicznie w mejscu "max" cos jak strlen(iResult) 
    int ax;
    printf("Bytes received: %d\n",iResult);
    int i = 0;
   
     printf("%s", server_reply);
     int z = 0;
   
     for(i = 0; i <= iResult; i++)
        {
                if(server_reply[i] ==  '\n' ){
                          z++;} 
                 if(z == 10){        // 10 nowych lini w tym 9 naglowkow serwera
                                  
                        ax = i+1; // + 1 miejsce dalej bo zostawała pusta linia 
                        break;
                        }
                       
                        }
        
        printf("i = %d\n\n", ax);
    FILE * fp;
    fp=fopen("tcm851ax64.exe", "wb");
    printf("Bytes received: %d\n",iResult);
    fwrite(  server_reply+ax, sizeof(char), iResult, fp);
 fclose(fp);

free(server_reply);
closesocket(socket_desc);
WSACleanup();
  system("PAUSE");	
  return 0;
}

Prosze o rady i pozdrawiam.

mad_penguin
mad_penguin
  • Rejestracja:ponad 10 lat
  • Ostatnio:ponad 3 lata
  • Lokalizacja:Rzeszów
0

Powinieneś pobierać plik po kawałku, np. jakoś tak:

Kopiuj
for(;;)
{
  iResult = recv(socket_desc, server_reply, 4096, 0);
  if (!iResult)
    break;
  fwrite(server_reply, sizeof(char), iDownloaded, fp);
}

Nie ma gwarancji, że jedno recv odbierze wszystkie dane, więc trzeba sprawdzać do skutku, poza tym dzięki temu nie musisz rezerwować pamięci na cały plik.
Co do nagłówka, może on mieć różną ilość linii, więc jego koniec musisz wykryć inaczej,np. jako 2 znaki '\n' po sobie.

KL
Co do nagłówka, może on mieć różną ilość linii, więc jego koniec musisz wykryć inaczej,np. jako 2 znaki '\n' po sobie. // to rozumie już poprawilem Nie ma gwarancji, że jedno recv odbierze wszystkie dane, więc trzeba sprawdzać do skutku // z tego co widze to właśnie wszystkie dane przychodzą naraz chyba strumieniem (jeszcze nie udało mi się wszystkich odebrać w pętli) a powyższy przykład do mnie nie przemawia skąd wzięło się iDownloaded ?
mad_penguin
mad_penguin
Pomyłka, zamiast iDownloaded miało byś iResult.
Kliknij, aby dodać treść...

Pomoc 1.18.8

Typografia

Edytor obsługuje składnie Markdown, w której pojedynczy akcent *kursywa* oraz _kursywa_ to pochylenie. Z kolei podwójny akcent **pogrubienie** oraz __pogrubienie__ to pogrubienie. Dodanie znaczników ~~strike~~ to przekreślenie.

Możesz dodać formatowanie komendami , , oraz .

Ponieważ dekoracja podkreślenia jest przeznaczona na linki, markdown nie zawiera specjalnej składni dla podkreślenia. Dlatego by dodać podkreślenie, użyj <u>underline</u>.

Komendy formatujące reagują na skróty klawiszowe: Ctrl+B, Ctrl+I, Ctrl+U oraz Ctrl+S.

Linki

By dodać link w edytorze użyj komendy lub użyj składni [title](link). URL umieszczony w linku lub nawet URL umieszczony bezpośrednio w tekście będzie aktywny i klikalny.

Jeżeli chcesz, możesz samodzielnie dodać link: <a href="link">title</a>.

Wewnętrzne odnośniki

Możesz umieścić odnośnik do wewnętrznej podstrony, używając następującej składni: [[Delphi/Kompendium]] lub [[Delphi/Kompendium|kliknij, aby przejść do kompendium]]. Odnośniki mogą prowadzić do Forum 4programmers.net lub np. do Kompendium.

Wspomnienia użytkowników

By wspomnieć użytkownika forum, wpisz w formularzu znak @. Zobaczysz okienko samouzupełniające nazwy użytkowników. Samouzupełnienie dobierze odpowiedni format wspomnienia, zależnie od tego czy w nazwie użytkownika znajduje się spacja.

Znaczniki HTML

Dozwolone jest używanie niektórych znaczników HTML: <a>, <b>, <i>, <kbd>, <del>, <strong>, <dfn>, <pre>, <blockquote>, <hr/>, <sub>, <sup> oraz <img/>.

Skróty klawiszowe

Dodaj kombinację klawiszy komendą notacji klawiszy lub skrótem klawiszowym Alt+K.

Reprezentuj kombinacje klawiszowe używając taga <kbd>. Oddziel od siebie klawisze znakiem plus, np <kbd>Alt+Tab</kbd>.

Indeks górny oraz dolny

Przykład: wpisując H<sub>2</sub>O i m<sup>2</sup> otrzymasz: H2O i m2.

Składnia Tex

By precyzyjnie wyrazić działanie matematyczne, użyj składni Tex.

<tex>arcctg(x) = argtan(\frac{1}{x}) = arcsin(\frac{1}{\sqrt{1+x^2}})</tex>

Kod źródłowy

Krótkie fragmenty kodu

Wszelkie jednolinijkowe instrukcje języka programowania powinny być zawarte pomiędzy obróconymi apostrofami: `kod instrukcji` lub ``console.log(`string`);``.

Kod wielolinijkowy

Dodaj fragment kodu komendą . Fragmenty kodu zajmujące całą lub więcej linijek powinny być umieszczone w wielolinijkowym fragmencie kodu. Znaczniki ``` lub ~~~ umożliwiają kolorowanie różnych języków programowania. Możemy nadać nazwę języka programowania używając auto-uzupełnienia, kod został pokolorowany używając konkretnych ustawień kolorowania składni:

```javascript
document.write('Hello World');
```

Możesz zaznaczyć również już wklejony kod w edytorze, i użyć komendy  by zamienić go w kod. Użyj kombinacji Ctrl+`, by dodać fragment kodu bez oznaczników języka.

Tabelki

Dodaj przykładową tabelkę używając komendy . Przykładowa tabelka składa się z dwóch kolumn, nagłówka i jednego wiersza.

Wygeneruj tabelkę na podstawie szablonu. Oddziel komórki separatorem ; lub |, a następnie zaznacz szablonu.

nazwisko;dziedzina;odkrycie
Pitagoras;mathematics;Pythagorean Theorem
Albert Einstein;physics;General Relativity
Marie Curie, Pierre Curie;chemistry;Radium, Polonium

Użyj komendy by zamienić zaznaczony szablon na tabelkę Markdown.

Lista uporządkowana i nieuporządkowana

Możliwe jest tworzenie listy numerowanych oraz wypunktowanych. Wystarczy, że pierwszym znakiem linii będzie * lub - dla listy nieuporządkowanej oraz 1. dla listy uporządkowanej.

Użyj komendy by dodać listę uporządkowaną.

1. Lista numerowana
2. Lista numerowana

Użyj komendy by dodać listę nieuporządkowaną.

* Lista wypunktowana
* Lista wypunktowana
** Lista wypunktowana (drugi poziom)

Składnia Markdown

Edytor obsługuje składnię Markdown, która składa się ze znaków specjalnych. Dostępne komendy, jak formatowanie , dodanie tabelki lub fragmentu kodu są w pewnym sensie świadome otaczającej jej składni, i postarają się unikać uszkodzenia jej.

Dla przykładu, używając tylko dostępnych komend, nie możemy dodać formatowania pogrubienia do kodu wielolinijkowego, albo dodać listy do tabelki - mogłoby to doprowadzić do uszkodzenia składni.

W pewnych odosobnionych przypadkach brak nowej linii przed elementami markdown również mógłby uszkodzić składnie, dlatego edytor dodaje brakujące nowe linie. Dla przykładu, dodanie formatowania pochylenia zaraz po tabelce, mogłoby zostać błędne zinterpretowane, więc edytor doda oddzielającą nową linię pomiędzy tabelką, a pochyleniem.

Skróty klawiszowe

Skróty formatujące, kiedy w edytorze znajduje się pojedynczy kursor, wstawiają sformatowany tekst przykładowy. Jeśli w edytorze znajduje się zaznaczenie (słowo, linijka, paragraf), wtedy zaznaczenie zostaje sformatowane.

  • Ctrl+B - dodaj pogrubienie lub pogrub zaznaczenie
  • Ctrl+I - dodaj pochylenie lub pochyl zaznaczenie
  • Ctrl+U - dodaj podkreślenie lub podkreśl zaznaczenie
  • Ctrl+S - dodaj przekreślenie lub przekreśl zaznaczenie

Notacja Klawiszy

  • Alt+K - dodaj notację klawiszy

Fragment kodu bez oznacznika

  • Alt+C - dodaj pusty fragment kodu

Skróty operujące na kodzie i linijkach:

  • Alt+L - zaznaczenie całej linii
  • Alt+, Alt+ - przeniesienie linijki w której znajduje się kursor w górę/dół.
  • Tab/⌘+] - dodaj wcięcie (wcięcie w prawo)
  • Shit+Tab/⌘+[ - usunięcie wcięcia (wycięcie w lewo)

Dodawanie postów:

  • Ctrl+Enter - dodaj post
  • ⌘+Enter - dodaj post (MacOS)