pobieranie pliku socket http c

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.

#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;
}
1
  1. 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);

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.

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.

#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.

0

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

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.

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