begin process at 2012 02 08 20:59:58
  Trouver un code source :
 
dans
 
Accueil > 

Code

 > 

Réseaux & Internet

 > TÉLÉCHARGER UN FICHIER (WIN32, SOCKETS)

TÉLÉCHARGER UN FICHIER (WIN32, SOCKETS)


 Information sur la source

Note :
10 / 10 - par 7 personnes
10,00 / 10

  • 1

  • 2

  • 3

  • 4

  • 5

  • 6

  • 7

  • 8

  • 9

  • 10
Catégorie :Réseaux & Internet Niveau :Initié Date de création :28/06/2004 Date de mise à jour :19/07/2004 02:37:34 Vu / téléchargé :15 283 / 1 592

Auteur : aardman

Ecrire un message privé
Site perso
Ce membre participe au partage de revenus publicitaires
Commentaire sur cette source (42)
Ajouter un commentaire et/ou une note


 Description

Voici un petit programme qui se connecte à un serveur http et qui télécharge un fichier (a partir d'une URL).
Une progressbar donne une idée de la progression du téléchargement. La vitesse de téléchargement est affichée, ainsi que le temp restant (théorique).

Lorsque l'on entre une URL et que l'on apuis sur Entrer, le programme lance un thread qui se charge du téléchargement. Le modele d'utilisation de winsock choisi est WSAEventSelect(...).
Le fichier téléchargé est copié dans 'mes documents'.

Source

  • #include <stdio.h>
  • #include <winsock2.h>
  • #include <windows.h>
  • #include <commctrl.h>
  • #include "resource.h"
  • #pragma comment(lib, "ws2_32.lib")
  • #pragma comment(lib, "comctl32.lib")
  • #define BUF_SIZE 8192 // 8KO
  • #define M(szTXT) SetWindowText(g_hSTA, szTXT)
  • HWND g_hSTA, g_hBAR, g_hSpeed, g_hDlg;
  • BOOL g_bDownloading = false;
  • BOOL CALLBACK AppDlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
  • DWORD WINAPI DownloadProc(void * szURL);
  • DWORD GetServerAddress(char * szURL);
  • int ParseHeaderHttp(char * buffer, int buffersize, int * sizeoffile);
  • char * GetFileNameFromURL(char * szURL);
  • int GetDocumentsDirectory(char * szbuf, int bufsize);
  • int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow)
  • {
  • WSADATA wsa;
  • if(WSAStartup(0x0202, &wsa)) return 0;
  • DialogBoxParam(hInstance, "MainDialog", 0, AppDlgProc, 0);
  • WSACleanup();
  • return 0;
  • }
  • BOOL CALLBACK AppDlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
  • {
  • static HANDLE hThread = 0;
  • static HWND hURL;
  • static char szURL[256];
  • switch(uMsg)
  • {
  • case WM_INITDIALOG:
  • InitCommonControls();
  • SetClassLong(hDlg, GCL_HICON,(long) "icone");
  • g_hDlg = hDlg;
  • hURL = GetDlgItem(hDlg, IDC_URL);
  • g_hBAR = GetDlgItem(hDlg, IDC_BAR);
  • g_hSpeed = GetDlgItem(hDlg, IDC_SPEED);
  • g_hSTA = GetDlgItem(hDlg, IDC_STA);
  • SetWindowText(g_hDlg, "Téléchargement");
  • return 1;
  • case WM_COMMAND:
  • switch(LOWORD(wParam))
  • {
  • case IDOK:
  • if(!g_bDownloading)
  • {
  • g_bDownloading = true;
  • GetWindowText(hURL, szURL, 256);
  • SendMessage(g_hBAR, PBM_SETPOS, 0, 0);
  • if(hThread) CloseHandle(hThread);
  • hThread = CreateThread(0, 0, DownloadProc, szURL, 0, 0);
  • }
  • return 0;
  • case IDCANCEL:
  • if(g_bDownloading)
  • {
  • if(IDNO == MessageBox(hDlg, "Fichier actuellement en cours de téléchargement.\r\nEtes vous sur de vouloir quitter ?", "Téléchargement en cours", MB_YESNO|MB_ICONWARNING))
  • return 0;
  • }
  • CloseHandle(hThread);
  • EndDialog(hDlg, 0);
  • }
  • }
  • return 0;
  • }
  • DWORD WINAPI DownloadProc(void * szURL)
  • {
  • SOCKET s;
  • sockaddr_in sin;
  • WSAEVENT hEvent[1];
  • WSANETWORKEVENTS NetworkEvent;
  • HANDLE hFile;
  • BYTE buffer[BUF_SIZE], *pBuffer;
  • DWORD dwSize = 0, dwRecu = 0, dwEcrit = 0, dwEcritTotal = 0;
  • DWORD dwLastEcritTotal = 0, dwDebit = 0, dwLastTickCount = 0;
  • DWORD dwTickCountDebut = 0, dwTempRestant = 0, dwDebitMoyen = 0;
  • char szTEMP[256], szLOCAL[256], *szFileName;
  • bool bHttpHeader = false;
  • // I: initialisation de la connexion
  • s = socket(AF_INET, SOCK_STREAM, 0);
  • if(s == -1) {
  • M("Erreur création socket.");
  • goto err_socket;}
  • sin.sin_family = AF_INET;
  • sin.sin_port = htons(80);
  • sin.sin_addr.S_un.S_addr = GetServerAddress((char*)szURL);
  • hEvent[0] = WSACreateEvent();
  • WSAEventSelect(s, hEvent[0], FD_READ | FD_CONNECT | FD_CLOSE);
  • connect(s, (sockaddr*)&sin, sizeof(sin));
  • M("Connexion au serveur...");
  • // II: initialisation du fichier local
  • if(!GetDocumentsDirectory(szTEMP, 256)) strcpy(szTEMP, "c:\\");
  • strcpy(szLOCAL, szTEMP);
  • szFileName = GetFileNameFromURL((char*) szURL);
  • strcat(szLOCAL, szFileName);
  • hFile = CreateFile(szLOCAL, FILE_ALL_ACCESS, FILE_SHARE_WRITE, 0, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0);
  • if(hFile == INVALID_HANDLE_VALUE)
  • {
  • M("Erreur fichier.");
  • goto err_socket;
  • }
  • // III: connexion, déconnexion, reception du fichier
  • while(1)
  • {
  • memset(&NetworkEvent, 0, sizeof(NetworkEvent));
  • WSAWaitForMultipleEvents(1, hEvent, 0, WSA_INFINITE, 0);
  • WSAEnumNetworkEvents(s, hEvent[0], &NetworkEvent);
  • if(NetworkEvent.lNetworkEvents & FD_CONNECT)
  • {
  • // erreur a la connexion
  • if(NetworkEvent.iErrorCode[FD_CONNECT_BIT]) {
  • M("Erreur lors de la connexion.");
  • CloseHandle(hFile); DeleteFile(szLOCAL);
  • goto err_socket;}
  • // si connexion ok, envoi de la requette
  • strcpy(szTEMP, "GET ");
  • strcat(szTEMP,(const char*) szURL);
  • strcat(szTEMP, " HTTP/1.0\r\n\r\n");
  • send(s, szTEMP, strlen(szTEMP), 0);
  • M("Envoi de la requette http au serveur...");
  • }
  • if(NetworkEvent.lNetworkEvents & FD_READ)
  • {
  • dwRecu = 0;
  • pBuffer = buffer;
  • dwRecu = recv(s,(char*) buffer, BUF_SIZE, 0);
  • //traitement du header
  • if(!bHttpHeader)
  • {
  • int iHeaderLen;
  • dwLastTickCount = dwTickCountDebut = GetTickCount(); // debut du download
  • iHeaderLen = ParseHeaderHttp((char*)buffer, BUF_SIZE,(int*) &dwSize);
  • if(!iHeaderLen)
  • {
  • M("Fichier introuvable.");
  • CloseHandle(hFile); DeleteFile(szLOCAL);
  • goto err_socket;
  • }
  • pBuffer += iHeaderLen;
  • dwRecu -= iHeaderLen;
  • bHttpHeader = true;
  • M("Header HTTP recu.");
  • }
  • // ecriture dans le fichier
  • WriteFile(hFile, pBuffer, dwRecu, &dwEcrit, 0);
  • dwEcritTotal += dwEcrit;
  • // affichage progressbar, infos, vitesse & temp restant
  • SendMessage(g_hBAR, PBM_SETPOS, (int)(100 * ((double)dwEcritTotal/(double)dwSize)), 0);
  • sprintf(szTEMP, "%s: %d/%d", szFileName, dwEcritTotal, dwSize);
  • M(szTEMP);
  • if(dwLastTickCount+1000 < GetTickCount())
  • {
  • // vitesse download
  • dwDebit = (dwEcritTotal - dwLastEcritTotal) / 1024;
  • dwLastTickCount = GetTickCount();
  • dwLastEcritTotal = dwEcritTotal;
  • sprintf(szTEMP, "%d ko/s", dwDebit);
  • SetWindowText(g_hSpeed, szTEMP);
  • // temp restant
  • dwDebitMoyen = dwEcritTotal / (GetTickCount()-dwTickCountDebut+1);
  • dwTempRestant = (dwSize-dwEcritTotal) / (dwDebitMoyen * 1000 + 1);
  • sprintf(szTEMP, "Téléchargement [%d %s]",
  • (dwTempRestant >= 60) ? dwTempRestant/60 : dwTempRestant,
  • (dwTempRestant >= 60) ? "min" : "sec");
  • SetWindowText(g_hDlg, szTEMP);
  • }
  • // téléchargement fini
  • if(dwSize == dwEcritTotal)
  • {
  • M("Téléchargement terminé.");
  • goto err_file;
  • }
  • }
  • if(NetworkEvent.lNetworkEvents & FD_CLOSE)
  • {
  • // verifie s'il ne reste plus rien a lire sur le socket
  • do {
  • memset(&NetworkEvent, 0, sizeof(NetworkEvent));
  • WSAEnumNetworkEvents(s, 0, &NetworkEvent);
  • if(NetworkEvent.lNetworkEvents & FD_READ)
  • {
  • dwRecu = 0;
  • dwRecu = recv(s,(char*) buffer, BUF_SIZE, 0);
  • WriteFile(hFile, buffer, dwRecu, &dwEcrit, 0);
  • dwEcritTotal += dwEcrit;
  • if(dwSize == dwEcritTotal) break;
  • }
  • }while(NetworkEvent.lNetworkEvents & FD_READ);
  • if(dwSize == dwEcritTotal) M("Téléchargement terminé.");
  • else M("Déconnecté du serveur.");
  • goto err_file;
  • }
  • }
  • err_file:
  • CloseHandle(hFile);
  • err_socket:
  • closesocket(s);
  • WSACloseEvent(hEvent[0]);
  • SendMessage(g_hBAR, PBM_SETPOS, 0, 0);
  • SetWindowText(g_hSpeed, 0);
  • g_bDownloading = false;
  • return 0;
  • }
  • // retourne un DWORD directement copiable dans sin_addr.S_un.S_addr (ip du serveur)
  • // szURL doit etre dans un buffer
  • DWORD GetServerAddress(char * szURL)
  • {
  • hostent * serv;
  • char * z; // z mettra le zero final
  • char * d = szURL; // d pointera sur le debut du nom du serveur
  • if(*d=='h' && *(d+1)=='t' && *(d+2)=='t' && *(d+3)=='p') d += 7; // 7 = http://
  • z = d;
  • while(*z != '/' && *z) z++; *z = 0;
  • serv = gethostbyname(d);
  • *z = '/';
  • if(!serv) return 0;
  • return (DWORD)*((DWORD*)serv->h_addr_list[0]);
  • }
  • // parse la 1ere réponse du serveur http apres une requette download de fichier
  • // extrait la taille du fichier, retourne la taille du header ou 0 si erreur
  • int ParseHeaderHttp(char * buffer, int buffersize, int * sizeoffile)
  • {
  • char * c, * f;
  • bool reponse_ok = false;
  • c = buffer;
  • f = c + buffersize; // c ne dois jamais depasser f
  • while(c < f)
  • {
  • // on verifie que le serveur réponds bien 200
  • if(*c=='2' && *(c+1)=='0' && *(c+2)=='0' && *(c+3)==32) reponse_ok = true;
  • // taille du fichier dans ligne de forme: "Content-Length: 123456"
  • if(*c =='\n') {
  • if(!strncmp(c+1,"Content-Length:", 15)) {
  • c += 17;
  • *sizeoffile = atoi(c);}}
  • // ligne vide = fin header http = debut fichier
  • if(*c=='\r' && *(c+1)=='\n' && *(c+2)=='\r' && *(c+3)=='\n' && reponse_ok == true && *sizeoffile) {
  • c += 4;
  • return (int)(c - buffer);}
  • c++;
  • }
  • return 0;
  • }
  • // retourne un pointeur sur le nom du fichier dans une URL
  • char * GetFileNameFromURL(char * szURL)
  • {
  • char * c = szURL;
  • while(*c) c++;
  • while(c > szURL && *c != '/') c--;
  • return (char*)++c;
  • }
  • // trouve le chemin de Mes Documents, rajoute le '\' final
  • int GetDocumentsDirectory(char *szbuf, int bufsize)
  • {
  • HKEY hKey;
  • int size, l;
  • char *c;
  • if(RegOpenKeyEx(HKEY_CURRENT_USER, "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders", 0, KEY_QUERY_VALUE, &hKey))
  • return 0;
  • size = bufsize;
  • l = RegQueryValueEx(hKey, "Personal", 0, 0, (BYTE*) szbuf, (DWORD*) &size);
  • RegCloseKey(hKey);
  • if(l) return 0;
  • c = szbuf + size - 1;
  • if(*(c-1) != '\\') {*c++ = '\\'; *c = 0;}
  • return (c - szbuf);
  • }
#include <stdio.h>
#include <winsock2.h>
#include <windows.h>
#include <commctrl.h>
#include "resource.h"
#pragma comment(lib, "ws2_32.lib")
#pragma comment(lib, "comctl32.lib")

#define BUF_SIZE 8192 // 8KO
#define M(szTXT) SetWindowText(g_hSTA, szTXT)

HWND g_hSTA, g_hBAR, g_hSpeed, g_hDlg;
BOOL g_bDownloading = false;

BOOL CALLBACK AppDlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
DWORD WINAPI DownloadProc(void * szURL);
DWORD GetServerAddress(char * szURL);
int ParseHeaderHttp(char * buffer, int buffersize, int * sizeoffile);
char * GetFileNameFromURL(char * szURL);
int GetDocumentsDirectory(char * szbuf, int bufsize);

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow)
{
	WSADATA wsa;
	if(WSAStartup(0x0202, &wsa)) return 0;
	DialogBoxParam(hInstance, "MainDialog", 0, AppDlgProc, 0);
	WSACleanup();
	return 0;
}

BOOL CALLBACK AppDlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
	static HANDLE hThread = 0;
	static HWND hURL;
	static char szURL[256];
	switch(uMsg) 
	{
	case WM_INITDIALOG:
		InitCommonControls();
		SetClassLong(hDlg, GCL_HICON,(long) "icone");
		g_hDlg = hDlg;
		hURL = GetDlgItem(hDlg, IDC_URL);
		g_hBAR = GetDlgItem(hDlg, IDC_BAR);
		g_hSpeed = GetDlgItem(hDlg, IDC_SPEED);
		g_hSTA = GetDlgItem(hDlg, IDC_STA);
		SetWindowText(g_hDlg, "Téléchargement");
	return 1;
	case WM_COMMAND:
		switch(LOWORD(wParam)) 
		{
		case IDOK:
			if(!g_bDownloading)
			{
				g_bDownloading = true;
				GetWindowText(hURL, szURL, 256);
				SendMessage(g_hBAR, PBM_SETPOS, 0, 0);
				if(hThread) CloseHandle(hThread);
				hThread = CreateThread(0, 0, DownloadProc, szURL, 0, 0);
			}
			return 0;
		case IDCANCEL:
			if(g_bDownloading)
			{
				if(IDNO == MessageBox(hDlg, "Fichier actuellement en cours de téléchargement.\r\nEtes vous sur de vouloir quitter ?", "Téléchargement en cours", MB_YESNO|MB_ICONWARNING))
					return 0;
			}
			CloseHandle(hThread);
			EndDialog(hDlg, 0);
		}
	}
return 0;
}

DWORD WINAPI DownloadProc(void * szURL)
{
	SOCKET s;
	sockaddr_in sin;
	WSAEVENT hEvent[1];
	WSANETWORKEVENTS NetworkEvent;
	HANDLE hFile;
	BYTE buffer[BUF_SIZE], *pBuffer;
	DWORD dwSize = 0, dwRecu = 0, dwEcrit = 0, dwEcritTotal = 0;
	DWORD dwLastEcritTotal = 0, dwDebit = 0, dwLastTickCount = 0;
	DWORD dwTickCountDebut = 0, dwTempRestant = 0, dwDebitMoyen = 0;
	char szTEMP[256], szLOCAL[256],  *szFileName;
	bool bHttpHeader = false;

	// I: initialisation de la connexion
	s = socket(AF_INET, SOCK_STREAM, 0);
	if(s == -1) {
		M("Erreur création socket."); 
		goto err_socket;}

	sin.sin_family = AF_INET;
	sin.sin_port   = htons(80);
	sin.sin_addr.S_un.S_addr = GetServerAddress((char*)szURL);

	hEvent[0] = WSACreateEvent();
	WSAEventSelect(s, hEvent[0], FD_READ | FD_CONNECT | FD_CLOSE);

	connect(s, (sockaddr*)&sin, sizeof(sin));
	M("Connexion au serveur...");

	// II: initialisation du fichier local 
	if(!GetDocumentsDirectory(szTEMP, 256)) strcpy(szTEMP, "c:\\");
	strcpy(szLOCAL, szTEMP);
	szFileName = GetFileNameFromURL((char*) szURL);
	strcat(szLOCAL, szFileName);
	hFile = CreateFile(szLOCAL, FILE_ALL_ACCESS, FILE_SHARE_WRITE, 0, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0);
	if(hFile == INVALID_HANDLE_VALUE)
	{
		M("Erreur fichier.");
		goto err_socket;
	}

	// III: connexion, déconnexion, reception du fichier
	while(1)
	{	
		memset(&NetworkEvent, 0, sizeof(NetworkEvent));

		WSAWaitForMultipleEvents(1, hEvent, 0, WSA_INFINITE, 0);
		WSAEnumNetworkEvents(s, hEvent[0], &NetworkEvent);

		if(NetworkEvent.lNetworkEvents & FD_CONNECT)
		{
			// erreur a la connexion
			if(NetworkEvent.iErrorCode[FD_CONNECT_BIT]) {
				M("Erreur lors de la connexion.");
				CloseHandle(hFile); DeleteFile(szLOCAL);
				goto err_socket;}

			// si connexion ok, envoi de la requette
			strcpy(szTEMP, "GET ");
			strcat(szTEMP,(const char*) szURL);
			strcat(szTEMP, " HTTP/1.0\r\n\r\n");
			send(s, szTEMP, strlen(szTEMP), 0);
			M("Envoi de la requette http au serveur...");
		}

		if(NetworkEvent.lNetworkEvents & FD_READ)
		{
			dwRecu = 0;
			pBuffer = buffer;
			dwRecu = recv(s,(char*) buffer, BUF_SIZE, 0);

			//traitement du header
			if(!bHttpHeader)
			{
				int iHeaderLen;
				dwLastTickCount = dwTickCountDebut = GetTickCount(); // debut du download
				iHeaderLen = ParseHeaderHttp((char*)buffer, BUF_SIZE,(int*) &dwSize);
				if(!iHeaderLen)
				{
					M("Fichier introuvable.");
					CloseHandle(hFile); DeleteFile(szLOCAL);
					goto err_socket;
				}
				pBuffer += iHeaderLen; 
				dwRecu  -= iHeaderLen;
				bHttpHeader = true;
				M("Header HTTP recu.");
			}

			// ecriture dans le fichier
			WriteFile(hFile, pBuffer, dwRecu, &dwEcrit, 0);
			dwEcritTotal += dwEcrit;
			
			// affichage progressbar, infos, vitesse & temp restant
			SendMessage(g_hBAR, PBM_SETPOS, (int)(100 * ((double)dwEcritTotal/(double)dwSize)), 0);

			sprintf(szTEMP, "%s: %d/%d", szFileName, dwEcritTotal, dwSize);
			M(szTEMP);

			if(dwLastTickCount+1000 < GetTickCount())
			{
				// vitesse download
				dwDebit = (dwEcritTotal - dwLastEcritTotal) / 1024;
				dwLastTickCount = GetTickCount();
				dwLastEcritTotal = dwEcritTotal;
				sprintf(szTEMP, "%d ko/s", dwDebit);
				SetWindowText(g_hSpeed, szTEMP);

				// temp restant
				dwDebitMoyen = dwEcritTotal / (GetTickCount()-dwTickCountDebut+1);
				dwTempRestant = (dwSize-dwEcritTotal) / (dwDebitMoyen * 1000 + 1);
				sprintf(szTEMP, "Téléchargement [%d %s]", 
					     (dwTempRestant >= 60) ? dwTempRestant/60 : dwTempRestant,
					     (dwTempRestant >= 60) ? "min" : "sec");
				SetWindowText(g_hDlg, szTEMP);
			}

			// téléchargement fini
			if(dwSize == dwEcritTotal)
			{
				M("Téléchargement terminé.");
				goto err_file;
			}
		}

		if(NetworkEvent.lNetworkEvents & FD_CLOSE)
		{
			// verifie s'il ne reste plus rien a lire sur le socket
			do {
				memset(&NetworkEvent, 0, sizeof(NetworkEvent));
				WSAEnumNetworkEvents(s, 0, &NetworkEvent);
				if(NetworkEvent.lNetworkEvents & FD_READ)
				{
					dwRecu = 0;
					dwRecu = recv(s,(char*) buffer, BUF_SIZE, 0);
					WriteFile(hFile, buffer, dwRecu, &dwEcrit, 0);
					dwEcritTotal += dwEcrit;
					if(dwSize == dwEcritTotal) break;
				}
			}while(NetworkEvent.lNetworkEvents & FD_READ);
	
			if(dwSize == dwEcritTotal) M("Téléchargement terminé.");
			else M("Déconnecté du serveur.");
			goto err_file;
		}
	}

err_file:
	CloseHandle(hFile);
err_socket:
	closesocket(s);
	WSACloseEvent(hEvent[0]);
	SendMessage(g_hBAR, PBM_SETPOS, 0, 0);
	SetWindowText(g_hSpeed, 0);
	g_bDownloading = false;
	return 0;
}

// retourne un DWORD directement copiable dans sin_addr.S_un.S_addr (ip du serveur)
// szURL doit etre dans un buffer
DWORD GetServerAddress(char * szURL)
{
	hostent * serv;
	char * z;              // z mettra le zero final
	char * d = szURL;      // d pointera sur le debut du nom du serveur
	if(*d=='h' && *(d+1)=='t' && *(d+2)=='t' && *(d+3)=='p') d += 7; // 7 = http://
	z = d;
	while(*z != '/' && *z) z++; *z = 0; 
	serv = gethostbyname(d);
	*z = '/';
	if(!serv) return 0;
return (DWORD)*((DWORD*)serv->h_addr_list[0]);
}

// parse la 1ere réponse du serveur http apres une requette download de fichier
// extrait la taille du fichier, retourne la taille du header ou 0 si erreur
int ParseHeaderHttp(char * buffer, int buffersize, int * sizeoffile)
{
	char * c, * f;
	bool reponse_ok = false;
	c = buffer;
	f = c + buffersize;     // c ne dois jamais depasser f

	while(c < f) 
	{
		// on verifie que le serveur réponds bien 200
		if(*c=='2' && *(c+1)=='0' && *(c+2)=='0' && *(c+3)==32) reponse_ok = true;

		// taille du fichier dans ligne de forme: "Content-Length: 123456"
		if(*c =='\n') {
			if(!strncmp(c+1,"Content-Length:", 15)) {
				c += 17;
				*sizeoffile = atoi(c);}}

		// ligne vide = fin header http = debut fichier
		if(*c=='\r' && *(c+1)=='\n' && *(c+2)=='\r' && *(c+3)=='\n' && reponse_ok == true && *sizeoffile) {
			c += 4;
			return (int)(c - buffer);}
		c++;
	}
return 0;
}

// retourne un pointeur sur le nom du fichier dans une URL
char * GetFileNameFromURL(char * szURL)
{
	char * c = szURL;
	while(*c) c++;
	while(c > szURL && *c != '/') c--; 
return (char*)++c;
}

// trouve le chemin de Mes Documents, rajoute le '\' final
int GetDocumentsDirectory(char *szbuf, int bufsize)
{
	HKEY hKey;
	int size, l;
	char *c;
	if(RegOpenKeyEx(HKEY_CURRENT_USER, "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders", 0, KEY_QUERY_VALUE, &hKey))
		return 0;
	size = bufsize;
	l = RegQueryValueEx(hKey, "Personal", 0, 0, (BYTE*) szbuf, (DWORD*) &size);
	RegCloseKey(hKey); 
	if(l) return 0;
	c = szbuf + size - 1;
	if(*(c-1) != '\\') {*c++ = '\\'; *c = 0;}   
	return (c - szbuf);
}




 Fichier Zip

Les Membres Club peuvent télécharger directement un fichier contenu dans le zip sans télécharger le zip en entier !

Télécharger le zip


 Historique

19 juillet 2004 02:37:34 :
petite modification de la syntaxe de la requette http qui n'etait pas "valide" selon la RFC HTTP/1.0.

 Sources du même auteur

Source avec Zip EDONKEY SEARCHER (SOCKET, WIN32)
Source avec Zip FONCTIONS IMPORTÉES/EXPORTÉES D'UN EXECUTABLE (WIN32)
Source avec Zip DES YEUX (WIN32)
Source avec Zip Source avec une capture DES CHIFFRES ET DES LETTRES (WIN32)
Source avec Zip DES CHIFFRES SANS LES LETTRES (WIN32)

 Sources de la même categorie

Source avec Zip SERVEUR MULTITHREAD [LINUX/WIN] par nipepsinicolas
Source avec Zip Source avec une capture SECURE REMOTE SHELL [WIN32] par ganjarasta
Source avec Zip Source avec une capture SUIVI DE PRODUCTION ONDULEUR PHOTOVOLTAÏQUE SOLARMAX par brunovan
Source avec Zip MINICHAT MULTI-CLIENT par wisar
SOCKET CPP par baptchr55

Commentaires et avis

Commentaire de LordBob le 28/06/2004 21:19:31

source de grande qualité qui montre bien comment telecharger un fichier depuis internet... de plus cela fesait un moment que je n'avais pas vu aardman trainé du coté de cppfrance...
enfin tres bon exemple...

Commentaire de aardman le 28/06/2004 23:55:03

Salut,

LordBob: merci pour le commentaire ! Comme tu dis, je trainais plus trop sur cppfrance à cause du bac mais maintenant je suis en vacance donc me revoila..

Brunews: merci pour les corrections, j'ai mis la source a jour avec la version "propre" de la fonction. C'etait la derniere fonction que j'avais a faire, je devais etre trop pressé de finir.

Commentaire de BruNews le 29/06/2004 00:13:22 administrateur CS

bah oui comme d'hab j'avais fait la 1ere correction comme un sauvage.
Saint Aigulf ça doit te causer ? Surement je fais un saut la-bas vers octobre, je te dirai.

Commentaire de aardman le 29/06/2004 01:02:53

oui, il me semble qu'il y a de jolies plages la bas, et en plus c'est pas trop loin de chez moi.

Commentaire de vecchio56 le 29/06/2004 01:21:00 administrateur CS

wunderbar!

Commentaire de neo_00110010101 le 29/06/2004 11:51:32

j'ai essayé avec l'image de ma page d'acceuil :
- le copier/coller marche
- la progress bar utile
- affichage temps restant (*)
- affichage de la vitesse

(*) petit problème, à la fin du téléchargement c'est toujours marqué [1 sec]

en plus, ça marche (bah oui !) et même si on arrête le DL, on a quand même un résultat (au moins pour les images)

Donc c'est excellent !!!!!!!!!!!!!!!! 10/10 (dommage que ça ne fait pas monter la note) ^^

Commentaire de Mingain le 02/07/2004 10:08:24

ma source ne fonctionne pas avec DevC++ ! Dommage ...

Commentaire de aardman le 02/07/2004 12:11:30

Salut,
Pour DevC++, je faut que tu enleves les #pragma comments du code et que tu link les lib directement dans les options du projet.

Commentaire de guyvdv le 10/09/2004 15:30:24

Bonjour Aardman ( en hollandais hommes de la terre )

Je suis plustot vb, mais j'essaye un peut le VC.
Ta source est excellente pour apprendre un peu le va et vient d'internet.
Mais ...
Le fichier exe fonctionne ( naturellement) tres bien mais je ne vois pas comment l'implenter dans VC de visualStudio6

Avec VB il suffi de double cliquer sur la source *.vbp mais cela je n'ai pas trouver pour VC6.

Peut tu m'aider

Guy van der velden

Commentaire de aardman le 10/09/2004 16:03:18

Salut,
Si tu as Visual Studio d'installé, normalement tu as juste a double-cliquer sur le fichier *.vcproj ou le *.sln pour ouvrir le projet.

Commentaire de BruNews le 10/09/2004 16:09:48 administrateur CS

aardman c'est VC6 pour lui.
Fais un new proj win32 APP GUI et VIDE.
Copie h, rc, cpp et ico dans dossier du proj. Dans VS tu fais insert fichiers existants *.* et tu select tout en 1 passe.
Devrait compiler.

Commentaire de guyvdv le 13/09/2004 17:52:25

Cher BruNews,

Dans VC6 il y a les possibilité d'ouvrire les project:
ATL Com App Wizard
Cluster Resource Type Wiz(ard)
Custom App Wiz
Database Project
Dev Studio Add-in Wiz
Extended Stord Proc Wiz
ISAPI Extension Wiz
MakeFile
MFC ActiveX Control Wiz
MFC App Wiz(DLL)
MFC App Wiz(EXE)
New Database Wiz
Utility Proj
Win32 Application
Win32 Console Appli
Win32 Dynamic-Link Library
Win32 Static Lib

J'ai choisis "Win32 Application"
J'ai construi un proj vide.
J'ai copié des fichiers:
  main.cpp
  res.rc
  resource.h
  url_code.sln
  url_code.vcproj
  Release
l ib
  main.dsp
  Debug
  main.ncb
  main.plg
  main.opt
  main.dsw

Ceux avec l'extension h,rc,cpp
ico il y en avai pas

Dans VisStudio VC 6 j'ai cherché pour trouver insert fichiers existants, mais je n'ai pas trouvé.

Et Maintenant ??

Guy

Commentaire de BruNews le 13/09/2004 18:00:08 administrateur CS

Je n'ai plus de VC6 depuis pas mal de temps mais y aurait pas un menu popup quand clic droit sur nom de projet dans la fenetre view project ? un truc 'insert files' ou machin de ce genre.
Les fichiers a inserer sont:
resource.h
resource.rc
1.ico
download.cpp

Commentaire de guyvdv le 13/09/2004 18:13:01

Esseque VC6 est trop vieux , il y a plus nouveau?
Tu travaille avec quoi ?

CA FONCTIONNE
A gauche dans FileView/SourceFiles un click droit et on a un menu ou on peut ajouter des fichier
(ceux-ci pour le amateur qui lisent avec nous)

Merci et je continu
Guy

Commentaire de BruNews le 13/09/2004 18:14:53 administrateur CS

Y a eu VS 2002 puis le 2003 depuis et dans quelques moi arrivera le 2005.

Commentaire de guyvdv le 13/09/2004 18:19:12

Petite Question :
Comment je mets une foto dans mon profile au lieu du point d'interogation

Guy

Commentaire de BruNews le 13/09/2004 18:36:20 administrateur CS

va dans les options de ton compte, menu a gauche.
Prepare avant un PETIT jpg au besoin.

Commentaire de vecchio56 le 15/09/2004 12:45:21 administrateur CS

66 ans... Je parie que guy est a gauche

Commentaire de BruNews le 15/09/2004 18:59:46 administrateur CS

Ne serait pas une combinaison de 6 ans pour l'un et 6 mois pour l'autre ?
Ou aurais je encore dit une connerie ?

Commentaire de HerveRV le 20/10/2004 00:16:29

très bien ce petit programme

par contre, j'ai fais un essai avec le fichier
http://www.kiss-cool.com/KissCool_2.mpg
ça fonctionne

le fichier
http://underfire.no-ip.com:8000/xoops/upload4u/ace1_wmv9.avi
donne "Erreur lors de la connexion."

et le fichier
http://www.sebastien-fritz.com/site/cv/cv.pdf
me donne ceci :

Envoi de la requette http au serveur...
Fichier introuvable. détails :

HTTP/1.1 404 Not Found
Date: Tue, 19 Oct 2004 21:53:45 GMT
Server: Apache
Connection: close
Content-Type: text/html; charset=iso-8859-1

<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<HTML><HEAD>
<TITLE>404 Not Found</TITLE>
</HEAD><BODY>
<H1>Not Found</H1>
The requested URL /site/cv/cv.pdf was not found on this server.<P>
<HR>
<ADDRESS>Apache/1.3.29 Server at www.sebastien-fritz.com Port 80</ADDRESS>
</BODY></HTML>

voila, donc je voudrais savoir pkoi ça fonctionne pas, alors dans un navigateur ça fonctionne !!!
merci

Commentaire de joeblack59 le 06/01/2005 18:54:56

ton programme m'a l'air vraiment intéressant, mais quand j'appuie sur entrée, il me fait rien! le telechargement ne se fait pas!
quand je vais au niveau du programme, il compile bien, mais il link pas : il me met deux erreurs :
LIBCD.lib(crt0.obj) : error LNK2001: unresolved external symbol _main
Debug/zzz.exe : fatal error LNK1120: 1 unresolved externals
je comprends pas à quoi, c du? c un pbm de librairies?
je suis débutant...
merci

Commentaire de BruNews le 06/01/2005 19:02:24 administrateur CS

Faut faire un projet Win32 GUI et non console.

Commentaire de aardman le 06/01/2005 19:08:58

Salut,
joeblack59 > il faut créer un projet win32 pour compiler le prog.

HerveRV (avec pas mal de retard) >
pour la deuxieme url, je pense que l'erreur se situe au niveau de la fonction qui analyse l'url, et donc la connexion doit se faire sur un mauvais host/port, d'ou l'erreur de connexion.
pour la troisieme url, je vois pas de probleme: mon prog affiche "Fichier introuvable", et le navigateur t'affiche "HTTP/1.1 404 Not Found".

Commentaire de HerveRV le 07/01/2005 01:45:54

aardman, le 3eme fichier est un fichier sur le ftp d'un pote ;)
il a du virer son fichier entre temps !

mais malgré tout, si tu peux mettre a jour ton programme pour qu'il marche avec tous type d'url, ça me serait utile a moi et des amis, car c vraiment pratique :p

Commentaire de aardman le 07/01/2005 02:04:48

Salut,
Le "HTTP/1.1 404 Not Found" est copié de ton premier post.
C'est ton navigateur qui a du te sortir ca (pas mon prog en tout cas).

Pour la mise à jour, je pense pas que ca va etre possible car je suis sur un autre projet qui me prend pas mal de temp, et en plus les examens approchent..

Commentaire de HerveRV le 07/01/2005 12:48:41

sisi, ça vient de ton programme, que j'ai modifié pour avoir des détails
je me rappelle plus comment, mais quand y a un probleme lors de la requette, j'ai demandé a voir un message d'erreur détaillé, que j'ai montré dans mon post

sinon, c pas grave, bosse bien ton projet, et bonne chance dans tes études ;)

Commentaire de Nebula le 25/07/2005 13:39:39

Source très instructive, merci ;-)

Commentaire de vecchio56 le 21/12/2005 13:48:24 administrateur CS

Serait-il possible de la même manière de télécharger plusieurs fichiers (envoyer plusieurs requêtes) à la suite, en ne se connectant qu'une fois. Ici on recoit un FD_CLOSE donc j'ai l'impression que non, mais peut être qu'il y a quelque chose à modifier pour que ce soit possible?
Merci

Commentaire de vecchio56 le 21/12/2005 14:46:46 administrateur CS

J'ai modifié ton code pour passer une requête HTTP 1.1
Visiblement c'est possible (http://www.w3.org/Protocols/rfc2616/rfc2616-sec8.html), mais je n'y arrive pas car je recois une demande de fermeture du serveur, alors que dans le rfc c'est écrit de supposer qu'il n'y en n'aura pas

Commentaire de aardman le 21/12/2005 17:38:17

Salut,
J'avoue que j'en ai aucune idée, as tu essayé de mettre un Connection: Keep-Alive du http/1.0 (pour "forcer" le serveur a garder la connexion) ?

Commentaire de vecchio56 le 21/12/2005 17:43:18 administrateur CS

J'ai essayé oui, mais le serveur me répond toujours
Connection: close dans le header de la réponse
C'est sans doute le serveur qui force la fermeture de la connexion, et visiblement on ne peut rien y faire

Commentaire de realic le 17/04/2007 17:23:37

Salut,

Ton programme ne gère pas la fonction "resume", ce qui peut être gênant, car si le dl plante pour x résons, faut tout recommencer.
Je vais essayer de faire cette fonction, mais si quelqu'un sait vraiment comment faire, qu'il me le dise, ou si il l'a déjà fait....

Très bon programme sinon.

Commentaire de aardman le 17/04/2007 18:52:14

Salut,
C'est un petit prog que j'avais posté comme ca, c'est pas vraiment utilisable en vrai pour les raisons que tu as cité. Pour que ca soit vraiment utilisable, faudrait gerer le resuming, splitter le download en plusieurs transferts, faire un traitement d'erreur plus poussé... en bref, faire un vrai download manager.

Pour gerer le resuming en http:

1) requete
On peut demander une partie du fichier en mettant le champ 'Range' dans la requete GET.
Les offsets que l'ont met dans le champ sont tous inclusifs.
Range: bytes=1000-2000 // demander de l'offset 1000 (inclus) a l'offset 2000 (inclus)
ou
Range: bytes=1000-     // demander tout le fichier a partir de l'offset 1000 (inclus)
On peut faire d'autres trucs plus compliqué avec Range, mais ca ca suffit pour faire du resuming.

2) reponse
En cas de success, le serveur réponds a une requete qui contient un 'Range' par un code 206 ('Partial Content' ou un truc du genre), et
place un champ 'Content-Range' de cette forme la:
Content-Range: bytes 3668247-7336494/11004733
qui contient de gauche a droite: l'offset de depart des données, l'offset de fin des données, et la taille du fichier.
Souvent, il met aussi un 'Content-Length', mais faut pas trop s'y fier et plutot regarder le 'Content-Range' (a mon avis).

3) support
Et aussi, le serveur indique qu'il supporte les requetes 'Range' en mettant 'Accept-Ranges: bytes' dans toutes ses réponses.

Commentaire de realic le 18/04/2007 09:25:03

Salut,

Merci pour cette explication, mais est-ce que le logiciel va comprendre qu'il faut qu'il ajoute les données trouvées aux données déjà existantes ?

Commentaire de realic le 18/04/2007 10:19:01

J'aurais voulu savoir :
WriteFile(hFile, pBuffer, dwRecu, &dwEcrit, 0);

Est-ce que cette fonction est équivalente à faire un seek ?

Car d'après ce que j'ai compris, si je veux faire des dl par parties, sans forcément que celles-ci se suivent, il faut que je puisse écrire à un endroit précis dans le fichier.
Donc, dwRecu correspond au début de l'endroit où l'on écrit, et &dwEcrit correspond à la fin de l'endroit où on écrit ?
par exemple, si on veut écrire des données entre les bytes 1234 et 4567, on écrit :
WriteFile(hFilen,pBuffer,1234,4567,0).
est-ce bien cela, ou est-ce que la fonction fait de manière différente ?

Commentaire de aardman le 18/04/2007 17:54:33

Salut,
Pas du tout, le WriteFile ne fait qu'ecrire sur le disque (comme fwrite). Pour specifier l'offset ou tu veux écrire, il faut utiliser SetFilePointer(comme fseek).

Commentaire de realic le 19/04/2007 09:08:28

OK merci, je vais regarder son fonctionnement.

Commentaire de realic le 25/04/2007 11:44:12

Salut,

Bon, le téléchargement "par partie" ne fonctionne pas du fait de "fichier corrompu".
Je vais te dire ce que je fais, et peut-être que quelqu'un pourra me dire pourquoi ca ne marche pas :
lors du premier lancement, j'arrête la fonction après récupération de la taille du fichier, donc après lecture dans le header. Puis je défini un pas d'avancement (1/15 de la taille du fichier)
pour les 14 autres lancements (pour tester le téléchargement par partie, en fait, je récupère le fichier découpé en 14 partie) :
pareil sauf que au lieu de faire un get "simple", je lui ajoute les propriétés "Range : bytes=tailleDebut-tailleFin"
tailleDebut est la valeur qu'avait tailleFin lors de la dernière exécution.
tailleFin est égale à sa valeur précédente+pas, sauf si cette valeur est inférieure à la taille réellement téléchargée (qui est sûre diffère à 99%).

Est-ce que quelqu'un aurait une idée? Je pense que c'est du au fait que je prenne en considération les header à chaque fois que je télécharge, mais je ne suis pas sur.

Commentaire de aardman le 25/04/2007 17:51:34

Salut,
C'est sur qu'avant d'ecrire dans le fichier, il faut prendre en compte les offsets de la reponse et pas ceux que tu as demandés, car ils peuvent etre different.
Par contre pour le fichier corrompu, je pense qu'il faut logguer toutes les requetes et les reponses et que tu fais, avec les offsets et les content-length des réponses, et verifier 'a la main'.

Commentaire de realic le 30/04/2007 08:58:21

Oui, en fait, j'ai mieux géré les offsets, et ca a marché. Pour tester, le mieux est de faire sur un fichier txt afin de voir si les phrases sont dans le bon ordre.
Mais maintenant ca marche parfaitement, merci pour ton aide.

Commentaire de Darksheep le 22/08/2007 11:48:24

Salut,ça m'a bien l'air d'une tres bonne source pourtant ça ne compile pas (devcpp)
j'ai bien viré les pragma et linké manuellement libcomctl32.a et libwsock32.a
pourtant j'obtient des   [Linker error] undefined reference to `WSACreateEvent@0' etc...
Une idée ?

Commentaire de Darksheep le 22/08/2007 11:50:46

Ok j'ai rien dit... 10/10 !

 Ajouter un commentaire




Nos sponsors


Sondage...

CalendriCode

Février 2012
LMMJVSD
  12345
6789101112
13141516171819
20212223242526
272829    

Consulter la suite du CalendriCode

Photothèque

 
Développement réalisé par Nicolas SOREL (Nix) avec l'aide de : Cyril DURAND et Emmanuel (EBArtSoft), Merci à Vincent pour ses précieux conseils.
CodeS-SourceS.com© Toute reproduction même partielle est interdite sauf accord écrit du Webmaster
CodeS-SourceS.com© est une marque déposée tous droits réservés

Google Coop CodeS-SourceS Google Coop CodeS-SourceS
Temps d'éxécution de la page : 5,398 sec (4)

Nous contacter | Annoncer sur CodeS-SourceS | Mentions légales