Сокет и получение данных

Discussion in 'С/С++, C#, Rust, Swift, Go, Java, Perl, Ruby' started by [NiGHT]DarkAngel, 23 Jun 2007.

Thread Status:
Not open for further replies.
  1. [NiGHT]DarkAngel

    [NiGHT]DarkAngel Elder - Старейшина

    Joined:
    29 Mar 2005
    Messages:
    131
    Likes Received:
    40
    Reputations:
    16
    Народ,я решил попробывать свои силы и сделать качалку фаилов )) , создал сокет, отправляю запрос http серверу на получение фаила,теперь вопрос е подскажите,где можно почитать про получение данных из сокета и сохрание на диске,как убрать из сокета ответ http сервера? Пишу на С++

    Зарание благодарен

    ЗЫ ногами сильно не бить,я только учусь ))
     
    #1 [NiGHT]DarkAngel, 23 Jun 2007
    Last edited: 23 Jun 2007
  2. GoreMaster

    GoreMaster Elder - Старейшина

    Joined:
    28 May 2007
    Messages:
    119
    Likes Received:
    32
    Reputations:
    4
    .data
    file db "C:\test.exe",0
    url db "your_host/file",0
    .code
    invoke URLDownloadToFile, NULL,ADDR url ,ADDR file ,0,NULL
    в wininet.dll функция
    http://www.wasm.ru/article.php?article=socketvssocket
    З.Ы.:на каком языке пишешь?
     
    #2 GoreMaster, 23 Jun 2007
    Last edited: 23 Jun 2007
  3. slesh

    slesh Elder - Старейшина

    Joined:
    5 Mar 2007
    Messages:
    2,702
    Likes Received:
    1,224
    Reputations:
    455
    2 GoreMaster Он укзал что пишет на С++. Твой пример хорошь, но на нем него нельзя нацепить прогрессбар ;)

    2 [NiGHT]DarkAngel Ты из соката через recv читай сначала данные во временный буфер. КОгда уже пройдут все HTTP заголовки. то потом начинай читать и сразу писать в файл.
     
    #3 slesh, 23 Jun 2007
    Last edited: 23 Jun 2007
    3 people like this.
  4. NetMan

    NetMan Elder - Старейшина

    Joined:
    9 Feb 2004
    Messages:
    121
    Likes Received:
    37
    Reputations:
    34
  5. je0n

    je0n Elder - Старейшина

    Joined:
    14 May 2006
    Messages:
    345
    Likes Received:
    96
    Reputations:
    41
    http://forum.web-hack.ru/index.php?showtopic=6328

    Тебе еще потребуются знание http-протокола. Юзай гугл. Вкратце: сначала посылаешь GET-запрос, затем получаешь в цикле через recv получаешь инфу. Что-то вроде этого:
    Code:
    char buf_in[10];
    int x;
    char page_text[50000];    //тут будет храниться все, что получаешь
    
    	x=recv(sock,buf_in,sizeof(buf_in)-1,0);
    	while(x>0)	
    	{
    		buf_in[x]=0;
    		lstrcat(page_text,buf_in);
    //		printf(buf_in);
    		x=recv(sock,buf_in,sizeof(buf_in)-1,0);
    	}
    
    Ну и еще пример функции. Я писал ее, чисто чтобы получать код страницы, а не файла. Но суть-то одна и таже. Ты и файл ей получишь.

    Code:
    char* GETRequest(char* server,char* page)
    {
    	WSADATA sock_info;
    	int err=WSAStartup(MAKEWORD(2,0),&sock_info);
    	if(err==SOCKET_ERROR)
    	{
    		printf("WSAStartup error");
    		return 0;
    	}
    	int sock;
    	struct sockaddr_in sa;
    	struct hostent* h;
    	char page_text[50000];
    	char buf_in[10];
    	char buf_out[500];
    	int x;
    	sa.sin_family=AF_INET;
    	sa.sin_port=htons(80);
    	h=gethostbyname(server);
    	memcpy(&sa.sin_addr,h->h_addr_list[0],h->h_length);
    	sock=socket(AF_INET,SOCK_STREAM,0);
    	if(connect(sock,(sockaddr*)&sa,sizeof(sa))<0)
    	{
    		printf("connect() error");
    		return 0;
    	}
    	lstrcpy(buf_out,"GET ");                  //Составляем GET-запрос
    	lstrcat(buf_out,page);
    	lstrcat(buf_out," HTTP/1.0\r\n");
    	send(sock,buf_out,lstrlen(buf_out),0);
    	lstrcpy(buf_out,"Host: izobilnik.ru\r\n");
    	send(sock,buf_out,lstrlen(buf_out),0);
    	lstrcpy(buf_out,"Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/x-shockwave-flash, application/vnd.ms-excel, application/vnd.ms-powerpoint, application/msword, application/xaml+xml, application/vnd.ms-xpsdocument, application/x-ms-xbap, application/x-ms-application, */*\r\n");
    	send(sock,buf_out,lstrlen(buf_out),0);
    	lstrcpy(buf_out,"User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; InfoPath.1; .NET CLR 1.1.4322; .NET CLR 2.0.50727; .NET CLR 3.0.04506.30)\r\n\r\n"); //заголовок User-Agent:
    	send(sock,buf_out,lstrlen(buf_out),0);
    	lstrcpy(page_text,"");
    	x=recv(sock,buf_in,sizeof(buf_in)-1,0);
    	while(x>0)
    	{
    		buf_in[x]=0;
    		lstrcat(page_text,buf_in);
    //		printf(buf_in);
    		x=recv(sock,buf_in,sizeof(buf_in)-1,0);
    	}
    	closesocket(sock);
    	return page_text;
    }
    
    пример использования:
    Code:
    char p[50000];
    lstrcpy(file,GETRequest("izobilnik.ru","/yourfile.zip"));
    
    по идее в p, должен быть ответ от сервера, вместе с файлом. Если файл большой, то увеличь значение в 50000
     
    #5 je0n, 24 Jun 2007
    Last edited: 24 Jun 2007
  6. [NiGHT]DarkAngel

    [NiGHT]DarkAngel Elder - Старейшина

    Joined:
    29 Mar 2005
    Messages:
    131
    Likes Received:
    40
    Reputations:
    16
    всем спасибо,завтро сдам экзамен и буду пробывать )
     
  7. [NiGHT]DarkAngel

    [NiGHT]DarkAngel Elder - Старейшина

    Joined:
    29 Mar 2005
    Messages:
    131
    Likes Received:
    40
    Reputations:
    16
    Так я научился получать данные и псиать в фаил )) , подскажите плз еще немножко,как убрать из фаила ответ Http-сервера ?или где почитать ))

    Зарание благодарен
     
  8. KEZ

    KEZ Ненасытный школьник

    Joined:
    18 May 2005
    Messages:
    1,604
    Likes Received:
    754
    Reputations:
    397
    получение данных из сокета - recv() и recvfrom(), тебе нужна первая
    сохранение на диске - запиши в файл. например CreateFile(), WriteFile(), CloseHandle()
    убрать ответ сервера - обреж все до двух \r\n подряд и дальше сохраняй.

    как я понимаю ты сначала записываешь в файл все, что вернул сервер. если да то пошли с нами долбаться и гонять по вене. на*** сохранять в файл ответ сервера? получаешь ответ, пока не встретятся \r\n два раза. затем читаешь в буффер скажем по 5кб данных и сохраняешь в файл. если надо эстетичнее - находи Content-Length: X и считывай X после переносов. если ещё эстетичнее - InternetOpen(), HttpOpenRequest(), HttpSendRequest() и так далее. например из illusion

    Code:
    
    DWORD Download( LPSTR server, LPSTR path, LPSTR local )
    {
    	HINTERNET hInternet = _InternetOpen( TEXT("Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US; rv:1.5a) Gecko/20030728 Mozilla Firebird/0.6.1"), INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0 );
    
    	if (!hInternet)
    		return 5;
    
        HINTERNET hConnect =
    		_InternetConnect(
    		hInternet,
    		TEXT( server ),
    		INTERNET_DEFAULT_HTTP_PORT,
    		NULL, NULL, INTERNET_SERVICE_HTTP, 0, (LPDWORD)1u );
    
    	if (!hConnect)
    		return 6;
    
    	HINTERNET hRequest = _HttpOpenRequest( hConnect, TEXT( "GET" ), TEXT( path ), NULL, NULL, 0, INTERNET_FLAG_KEEP_CONNECTION, (LPDWORD)1 );
    	if (!hRequest)
    		return 7;
    
    	BOOL bSend = _HttpSendRequest( hRequest, NULL, NULL, NULL, NULL );
    	if (!bSend) return 8;
     
    	/* delete old file */
    	_DeleteFile( local );
    
    	/* create new */
    	HANDLE hFile = _CreateFile( local, GENERIC_WRITE, NULL, NULL, CREATE_NEW, NULL, NULL );
    	if (hFile == INVALID_HANDLE_VALUE) return 9;
    
    	DWORD dwBytesRead, dwBytesWrite;
    	BYTE szData[1024];
    	BYTE ret = 0;
    
    	for (;;)
    	{
    		if (!Opt_HTTP_Download.started)
    		{
    			ret = 1;
    			break;
    		}
    
    		BOOL bRead = _InternetReadFile( hRequest, szData, sizeof( szData ) - 1, &dwBytesRead );
    		Opt_HTTP_Download.filesize += 1024; //dwBytesRead;
    
    		if (!bRead || !dwBytesRead) break;
    
    		szData[dwBytesRead] = 0;
    		if (!_WriteFile( hFile, szData, dwBytesRead, &dwBytesWrite, NULL )
    			|| !dwBytesWrite) break;
    	}
    
    	_CloseHandle( hFile );
    	_InternetCloseHandle( hRequest );
    	_InternetCloseHandle( hConnect );
    	_InternetCloseHandle( hInternet );
    
    	if (ret) return 255; else return 1;
    }
    
    
    _funcname заменяй на funcname
    всякие if (!Opt_HTTP_Download.started) уберай

    je0n, пиздец ты друг накатал ***ни)
    может будет по байту запрос составлять и отсылать по байту?
    так нельзя?
    sprintf( request, "GET %s HTTP/1.1\r\nHost: %s\r\n\r\n", path, host );
    send( s, request, strlen( request ), 0 );

    *** ты из файла, в котором встречаются нулевые байты, запишешь таким образом данные

    угу, а потом return page_text ... да, все-таки некоторым больше подойдет делфи

    ну а тут вообще без комментариев

    Гениальный совет кодера. Не даром у тебя написано "asm+delphi". Нахер спрашивается читать сначала в буффер, выделяя -неизвестное- кол-во памяти, а потом в файл, если можно сразу пропустить заголовки и в файл?

    PS
    кез спит, сейчас разбужу, забыла какая есть ф-ия ещё API там... а. всмысле это нерд пишет) приветик)
     
    #8 KEZ, 27 Jun 2007
    Last edited: 27 Jun 2007
    3 people like this.
  9. _Great_

    _Great_ Elder - Старейшина

    Joined:
    27 Dec 2005
    Messages:
    2,032
    Likes Received:
    1,119
    Reputations:
    1,139
    Если у тебя с алгоритмикой все в порядке, должен догадаться (RFC почитать что-ли, ну или хз), что данные отделяются от заголовка последовательностью \r\n\r\n
    Ищи эти 4 байта в ответе сервера.

    ЗЫ. это если протокол 1.0. У протокола 1.1 там свои выкрутасы еще есть.

    Ну.. для протокола хттп 1.0 достаточно просто сохранять тупо всё, пока сокет не закроют на сервере.
    Для протокола 1.1 - там передается отдельно длина запроса, и после передачи всего тела сокет не закрывается, так что если этого не учесть, твоя прога повиснет, когда получит все данные, и отвиснет только после разрыва соединения по тайм-ауту
     
    #9 _Great_, 27 Jun 2007
    Last edited: 27 Jun 2007
    1 person likes this.
  10. KEZ

    KEZ Ненасытный школьник

    Joined:
    18 May 2005
    Messages:
    1,604
    Likes Received:
    754
    Reputations:
    397
    ну это ясно, только мы пишем в заголовке HTTP/1.0 и все путем)
     
    #10 KEZ, 27 Jun 2007
    Last edited by a moderator: 27 Jun 2007
  11. slesh

    slesh Elder - Старейшина

    Joined:
    5 Mar 2007
    Messages:
    2,702
    Likes Received:
    1,224
    Reputations:
    455
    2 Kez млин. конечно нужен временный буфер куда читать.
    я просто навренео не правильно выразился. я имел в виду троковую переменну. в которую читать данные и искать конец Http заголовка.
     
  12. sn0w

    sn0w Статус пользователя:

    Joined:
    26 Jul 2005
    Messages:
    1,023
    Likes Received:
    1,296
    Reputations:
    327
    Http заголовок завершается двойным Crlf. дальше идут данные.
     
    1 person likes this.
  13. [NiGHT]DarkAngel

    [NiGHT]DarkAngel Elder - Старейшина

    Joined:
    29 Mar 2005
    Messages:
    131
    Likes Received:
    40
    Reputations:
    16
    Так вроде чето получилось написать,хтмл странички принимаю без проблем,а вот с остальным rar, exe и тд. как то не важно,куда то теряются данные при передачи ((

    Если не трдуно посмотрите пожалйуста исходник и моно носом ткнуть что и где неправильно))

    Ногами сильно не бить , я только учусь и в этой проге куча всяких недостатков и багов,но все ранво зарание всем спасибо за все )


    Code:
    //---------------------------------------------------------------------------
    
    #include <vcl.h>
    #include <iostream.h>
    #include <conio.h>
    #include <winsock2.h>
    #include <stdlib.h>
    #include <stdio.h>
    #pragma hdrstop
    
    //---------------------------------------------------------------------------
    
    class my_socket
    {
    public:
    SOCKET client;
    my_socket();
    ~my_socket();
    
    int error() {cout << "!!! Owu6ka !!!" << WSAGetLastError() << endl; return 1;}
    int sends(char *byf,SOCKET client);
    };
    
    my_socket::my_socket()
    {
    WSAData w;
    int error=WSAStartup (0x0202, &w);
    if (error)
     {
     cout << "Neizvestna9 owubka :( " <<endl;
    
     }
     if (w.wVersion != 0x0202)
     { // íå òà âåðñèÿ ñîêåòîâ!
    WSACleanup (); // âûãðóæàåì  ws2_32.dll
    
     }
    
    cout << "Rabotaet konstructor" << endl;
    }
    
    my_socket::~my_socket()
    {
    
    WSACleanup();
    cout << "Rabotaet destructor " << endl;
    }
    
    int my_socket::sends(char *buff, SOCKET client)
    {
    int rVal=0;
    
    rVal = send(client,buff,strlen(buff),0);
    
        if(rVal == SOCKET_ERROR)
        {
            cout <<"Failed send()"<<endl;
            return 1;
        }
        else
        {cout << " Yspewno peredalos' " << endl;}
        return 0;
    }
    
    #pragma argsused
    int main(int argc, char* argv[])
    {
    cout << "Na4alo rabotu programmu" << endl;
    my_socket my;
    SOCKET s;
    sockaddr_in target;
    
    
    s = socket (AF_INET, SOCK_STREAM, 0); // Ñîçäà¸ì ñîêåò
    
    target.sin_family = AF_INET;           // ñåìåñòâî àäðåñîâ - Èíòåðíåò
    target.sin_port = htons (80);        // ïîðò ñåðâåðà
    target.sin_addr.s_addr = inet_addr ("127.0.0.1");
    //target.sin_addr.s_addr = inet_addr ("87.224.128.10");  // IP-àäðåñ ñåðâåðà
    int rVal=0;
    rVal=connect(s,(LPSOCKADDR)&target, sizeof(target));
     if(rVal==SOCKET_ERROR)
        {
            cout << "Failed connection" << endl;
            return 1;
        }
      else {cout << " Socket yspewno soedenils9" << endl;}
    
    my.sends("GET http://127.0.0.1/files/my.txt HTTP/1.0\r\n\r\n",s);
    my.sends("User-Agent: myDownload 0.1\r\n\r\n",s);
    my.sends("Accept: */*\r\n\r\n",s);
    my.sends("Host: 127.0.0.1 \r\n\r\n",s);
    //my.sends("Connection: close\r\n\r\n",s);
    
    
    char buf_in[8];
    int x;
    char page_text[190000];    //òóò áóäåò õðàíèòüñÿ âñå, ÷òî ïîëó÷àåøü
    FILE *tele;
    if ((tele = fopen("my.txt","w+b")) == NULL)
    {
     cout << " Open file error " <<endl;
     getch();
     return -1;
    }
    
    x=recv(s,buf_in,sizeof(buf_in)-1,0);
    
    while(x>0)
    {
     buf_in[x]=0;
     lstrcat(page_text,buf_in);
     //cout << buf_in;
     //getch();
     x=recv(s,buf_in,sizeof(buf_in)-1,0);
    }
    
    cout << endl << "strlen(page_text) = " << strlen(page_text) << endl;
    
    int i;
    for (i=0;i<strlen(page_text);i++)
    {
     if ((page_text[i]=='\r') && (page_text[i+1]=='\n') && (page_text[i+2]=='\r')&& (page_text[i+3]=='\n'))
      {
       cout << "Est' taka9 stroka i = " << i << endl;  break;
      }
    
    }
    int p,b,q;
    p=i+4;
    
    q=(strlen(page_text)-p);
    char *stroka;
    cout << "p = " << p<< endl;
    cout << "strlen = " << q << endl;
    for (b=p;b<strlen(page_text);b++)
    {
    cout << "b= " <<b << endl;
    stroka=&(page_text[b]);
    fwrite(stroka,strlen(stroka),1,tele); break;
    }
        closesocket(s);
        my.~my_socket();
    getch();
            return 0;
    }
    //---------------------------------------------------------------------------
    
    
    
     
    1 person likes this.
  14. KEZ

    KEZ Ненасытный школьник

    Joined:
    18 May 2005
    Messages:
    1,604
    Likes Received:
    754
    Reputations:
    397
    Б**** сколько ещё раз написать тебе что lstrcat - присоединяет СТРОКУ. Строка заканчивается нулевым символом. А у тебя содержимое рар или ехе может иметь что угодно, в том числе и нули.

    И ещё, мне кажется что тебе рановато использовать КЛАССЫ. Ещё и такие бессмысленные как в данном случае. Спрашивается - нахера они тебе тут нужны?
     
    #14 KEZ, 1 Jul 2007
    Last edited by a moderator: 6 Jul 2007
    1 person likes this.
  15. NetMan

    NetMan Elder - Старейшина

    Joined:
    9 Feb 2004
    Messages:
    121
    Likes Received:
    37
    Reputations:
    34
    Sorry 2 all...
    Вот накатал скачивание при помощи класса CInternetFile библиотеки MFC.
    Code:
    void DownloadFile(LPCSTR pstrURL,LPCSTR lpszFileName)
    {
    	CInternetSession inetSession;
    	CInternetFile *inetFile = (CInternetFile *) inetSession.OpenURL(pstrURL, 1, INTERNET_FLAG_TRANSFER_BINARY | INTERNET_FLAG_DONT_CACHE);
    	CFile file(lpszFileName,CFile::modeCreate | CFile::modeWrite | CFile::typeBinary); 
    
    	char buf[8192];
    	DWORD dwBytesRead;
    	while (dwBytesRead=inetFile->Read(buf, sizeof(buf)))
    		file.Write(buf, dwBytesRead);
    	
    	inetFile->Close();
    	delete inetFile;
    	inetSession.Close();
    }
     
  16. A110ut

    A110ut Elder - Старейшина

    Joined:
    31 Dec 2005
    Messages:
    505
    Likes Received:
    263
    Reputations:
    92
    NetMan, может проще взять Download Master ?

    [NiGHT]DarkAngel, не поддавайся на провокации. еб*аш Свой довнлоадер пока не заработает. если не получается по другому, то нужно учится и на своих ошибках..
     
  17. da_ff

    da_ff Elder - Старейшина

    Joined:
    11 Jul 2006
    Messages:
    118
    Likes Received:
    22
    Reputations:
    26
    с начала не читал так что есди не попаду в тему то просто не обращайте внимания

    FILE *out;
    while(x=ecv(s,buf_in,sizeof(buf_in)-1,0))
    {
    buf_in[x]=0;
    fwrite(buf_in,x,1,out);
    }

    че то типа того
     
  18. Ni0x

    Ni0x Elder - Старейшина

    Joined:
    27 Aug 2006
    Messages:
    338
    Likes Received:
    157
    Reputations:
    37
    da_ff, исправь ecv на recv
     
    1 person likes this.
  19. KEZ

    KEZ Ненасытный школьник

    Joined:
    18 May 2005
    Messages:
    1,604
    Likes Received:
    754
    Reputations:
    397
    Я не знаю даже. Может вам картинку с комиксом нарисовать надо или под музыку песню написать где рассказывается на китайском что strcat() прикрепляет строку к строке а не массив байт к массиву байт и что через MFC делать скачивание файла - все равно что через 3DS MAX рисовать точку на экране?
     
  20. _Great_

    _Great_ Elder - Старейшина

    Joined:
    27 Dec 2005
    Messages:
    2,032
    Likes Received:
    1,119
    Reputations:
    1,139
    Блин, стоит только отойти, уже флейма разведут на Н страниц. Таких тем в инете полно! Исходников тоже!
    На крайняк если ТС ничего не найдет (вероятность менее 1%), то я потом выложу в паблик Antichat Web Tool, где скачивание страницы реализовано через чистые сокеты.

    В двух словах:

    Code:
    SOCKET s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    SOCKADDR_IN sa = {0};
    sa.sin_family = AF_INET;
    HOSTENT* phe = gethostbyname("google.ru");
    *(DWORD*)&sa.sin_addr.s_addr = *(DWORD*)phe->h_addr_list[0];
    sa.sin_port = htons(80);
    connect( s, &sa, sizeof(sa) );
    
    const int bsize = 1024*1024;  // 1 megabyte
    char *buffer = new char[bsize];
    wsprintf( buffer, "GET http://google.ru/ HTTP/1.0\r\nHost: google.ru\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 );
    char *body = strstr( buffer, "\r\n\r\n" );
    body += 4; // strlen of \r\n\r\n
    
    // now buffer contains full response, body contains only response body
    
    delete buffer;
    
    Скачка файла через MFC - из пушки по воробьям

    Тема закрыта
     
    #20 _Great_, 7 Jul 2007
    Last edited: 7 Jul 2007
Thread Status:
Not open for further replies.