Передача файла по http используя только сокеты
Если для файлов с текстовы содержанием все предельно ясно(подключится к вебсерверу,отправить что то типа"GET http://targethost.com/test.txt HTTP/1.0\r\nHost: targethost.com\r\n\r\n",и из полученного текста с помощью strtok и strstr вырезать все нужное).То как быть с другими файлами?
вот только наверное надо указывать MIME
вот только наверное надо указывать MIME
Можно попдробней а то тут http://www.lib.ru/WEBMASTER/rfc2068/ о MIME неслова
а после \r\n\r\n ловишь столько байт сколько сказано в Content-Length.
а после \r\n\r\n ловишь столько байт сколько сказано в Content-Length.
это если Transfer-Encoding дефолтный ;)
а если нет, то прийдётся декодировать из какого-нибудь chunked
а если нет, то прийдётся декодировать из какого-нибудь chunked[/QUOTE]
это уже другой вопрос :)
ну на самом деле да вообще... если не говорить в запросе, что ты умеешь chunked, то приличный сервер его и не пришлёт :)
так что, просто смотришь сколько контента должно быть и столько его и читаешь
[/QUOTE]
<SCORP>, попробуй скажи это гуглу ))
или у них неприличный сервер?
[QUOTE=<SCORP>;208755]
так что, просто смотришь сколько контента должно быть и столько его и читаешь[/QUOTE]
И рано или поздно натыкаешся на остутвие контента там где он должен быть. )) Есть спецификация протокола, и ее нужно уметь поддерживать. )
{
WSADATA wsd;
WSAStartup(MAKEWORD(1,1),&wsd);
hostent *h;
char *Ip=new char[150];
h=gethostbyname(host);
sprintf(Ip,"%d.%d.%d.%d",(unsigned char)h->h_addr_list[0][0],(unsigned char)h->h_addr_list[0][1],(unsigned char)h->h_addr_list[0][2],(unsigned char)h->h_addr_list[0][3]);
SOCKADDR_IN ss;
ss.sin_family = AF_INET;
ss.sin_addr.s_addr =inet_addr(Ip);
ss.sin_port = htons(80);
SOCKET s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
connect( s,(sockaddr *)&ss, sizeof(ss) );
const int bsize = 1024*1024;
char *buffer = new char[bsize];
strcpy(buffer,"GET /");
strcat(buffer,uri);
strcat(buffer," HTTP/1.0\r\nHost: ");
strcat(buffer,host);
strcat(buffer,"\r\n\r\n");
send( s, buffer, strlen(buffer), 0 );
int bytes = 0, pos = 0;
do
{
bytes = recv( s, buffer+pos, bsize-pos, 0 );
if( !(bytes>0) )
break;
pos += bytes;
buffer[pos] = 0;
}
while(1);
closesocket( s );
printf(buffer);
char *body = strstr( buffer, "\r\n\r\n" );
body += 4;
WSACleanup();
return(body);
}
Но если с её помощью попытатся получить к примеру *.exe то вернется только 3 буквы : MZP(насколько я понимаю обозначающих тип файла).Хотя Content-Length тмеет правильный размер файла.Так как нужно правильно сформировать запрос а потом принять ответ от сервера,чтобы можно было вытащить из этого ответа содержимое нетекстового файла?
так что данные прочитаны и память под них выделена. просто ты их не видишь.
я думаю, что тебе просто надо писать полученые данные не в char*, а в какой-то поток
так что данные прочитаны и память под них выделена. просто ты их не видишь.
я думаю, что тебе просто надо писать полученые данные не в char*, а в какой-то поток[/QUOTE]
Мне раньше не приходилось с тким сталкиватся, можно поподробней?
просто нужно отделять мух от котлет и не маяться нулями ))
{
WSADATA wsd;
WSAStartup(MAKEWORD(1,1),&wsd);
hostent *h;
char *buffer2=new char[1024*1024];
char *content;
DWORD n;
char *Ip=new char[150];
h=gethostbyname(host);
sprintf(Ip,"%d.%d.%d.%d",(unsigned char)h->h_addr_list[0][0],(unsigned char)h->h_addr_list[0][1],(unsigned char)h->h_addr_list[0][2],(unsigned char)h->h_addr_list[0][3]);
SOCKADDR_IN ss;
ss.sin_family = AF_INET;
ss.sin_addr.s_addr =inet_addr(Ip);
ss.sin_port = htons(80);
SOCKET s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
connect( s,(sockaddr *)&ss, sizeof(ss) );
const int bsize = 1024*1024;
char *buffer = new char[bsize];
strcpy(buffer,"GET /");
strcat(buffer,uri);
strcat(buffer," HTTP/1.0\r\nHost: ");
strcat(buffer,host);
strcat(buffer,"\r\n\r\n");
send( s, buffer, strlen(buffer), 0 );
int bytes = 0, pos = 0;
do
{
bytes = recv( s, buffer+pos, bsize-pos, 0 );
if( !(bytes>0) )
break;
pos += bytes;
buffer[pos] = 0;
}
while(1);
strcpy(buffer2,buffer);
content=strstr(buffer2,"Content-Length:");
content+=15;
strtok(content,"/n Last");
int size=atoi(content);
closesocket( s );
char *body = strstr( buffer, "\r\n\r\n" );
body += 4;
WSACleanup();
HANDLE f=CreateFile("\\\\.\\C:\\cod\\out.exe",GENERIC_WRITE, FILE_SHARE_WRITE, NULL, CREATE_ALWAYS,FILE_FLAG_RANDOM_ACCESS, NULL);
WriteFile(f,body,size,&n,NULL);
CloseHandle(f);
delete buffer;
delete buffer2;
delete Ip;
delete host;
delete uri;
}
Спасибо всем кто помог.
const int bsize = 1024*1024;
char *buffer = new char[bsize];
Что по твоему произойдет при попытке скачать файл больше 1мб?
buffer[pos] = 0;
не правильно, ибо имеет смысл только при работе со строками, но не в общем случае.
HANDLE f=CreateFile("\\\\.\\C:\\cod\\out.exe",GENERIC_WRITE, FILE_SHARE_WRITE, NULL, CREATE_ALWAYS,FILE_FLAG_RANDOM_ACCESS, NULL);
Зачем так хитро - что бы просто не открыть файл?
Ну и еще кучка маленьких косячков по коду.
aks, +1. ну я про массив byte так, для приличия сказал ( unsigned char, сам посмотрел, понял что не то ;) ). так что естессна лучше писать в файл сразу :)
char *buffer = new char[bsize];
_nic, ну я ш тебе говорил ))) ищи Content-Length и читай столько, сколько там написано :)
Не совсем. Content-Length может и не быть. Если его нет - надо уметь и такую ситуацию обрабатывать.
Вот попробуй ссылку:
http://maps.google.com/maps?q=55.751463,37.617273
и глянь какой там Content-Length. А гугл всеже один из очень посещаемых и авторитетных сайтов )
в общем, посмотри что там вообще происходит-то :)
Date: Thu, 06 Sep 2007 19:26:23 GMT
Server: ZX_Spectrum/1997 (Sinclair_BASIC)
Set-Cookie: nuid=1607883821189106783; path=/; expires=Sun, 03-Sep-17 19:26:23 GM
T; domain=.narod.ru
Last-Modified: Mon, 25 Mar 2002 01:27:04 GMT
ETag: "da806-a49a6-3c9e7ce8"
Accept-Ranges: bytes
Content-Length: 674214
Connection: close
Content-Type: video/x-ms-asf
Когда качаю этот файл http://level-0.narod.ru/video/nagasaki.asf
Проблема в том что после компиляции сразуже получаю ошибку по этой строке "strtok(content,"/n Last");"
http://img105.imageshack.us/my.php?image=er2lr0.jpg
прикол в том что эта ошибка получается именно при нажатие F9 , но если запустить собранное приложение то все ОК.Мистика какая то :confused: .Я конечно понимаю что ошибка может быть вызвана ограничением стековой памяти до 1 мб, но мне просто интересно почему невозникает ошибка при запуске уже собранной программы.
ЗЫ:использую борланд С++ билдер 6й версии
Мда,что то я в последнее время невнимательный :(