winsock, какой должен быть запрос?

Discussion in 'С/С++, C#, Rust, Swift, Go, Java, Perl, Ruby' started by wolmer, 30 Nov 2010.

  1. wolmer

    wolmer Member

    Joined:
    12 May 2009
    Messages:
    438
    Likes Received:
    97
    Reputations:
    9
    Пытаюсь скачать картинку (вот эту: http://ru.fishki.net/picsw/112010/23/joke.jpg)
    Делаю я это так:
    Code:
    #define WIN32_LEAN_AND_MEAN
    
    #include <windows.h>
    #include <stdio.h>
    #include <winsock2.h>
    
    #pragma comment( lib, "wsock32.lib" )
    
    sockaddr_in server_info;
    
    int get_jpg(char http_site[64])
    {
    	int sock;
    	sock = socket(AF_INET, SOCK_STREAM, 0);
    
    	if (connect(sock, (struct sockaddr*)&server_info, sizeof(server_info)) == 0)
    	{
    		char send_packet[4024], recv_packet[4097], temp[4024];
    		sprintf(temp, "GET %s HTTP/1.0\r\nUser-Agent: Opera/10.60 (Windows NT 6.1; U; ru) Presto/2.6.30 Version/10.60\r\nHost: ru.fishki.net\r\nConnection: Close\r\n\r\n", http_site);
    		strcpy(send_packet, temp);
    
    		send(sock, send_packet, strlen(send_packet), 0);
    		int i3 = 0, last_res, int_temp;
    
    		while (1)
    		{
    			int_temp = recv(sock, recv_packet, 4096, 0);
    			if ((int_temp == 0) || (int_temp == -1)) break;
    			i3 += int_temp;
    			ZeroMemory(recv_packet, 4096);
    		}
    	}
    
    	closesocket(sock);
    	return 0;
    }
    
    int main()
    {
    	WSADATA ws;
    	WSAStartup(MAKEWORD(2, 2), &ws);
    
    	server_info.sin_addr.s_addr = inet_addr("82.98.86.161");
    	server_info.sin_port = htons(80);
    	server_info.sin_family = AF_INET;
    
    	get_jpg("http://ru.fishki.net/picsw/112010/23/joke.jpg");//recv возврашает -1
    	//get_jpg("http://ru.fishki.net/picsw/index.php");//recv не возвращает 0
    }
    Но recv возвращает -1! Хотя если попробывать запросить страницу http://ru.fishki.net/picsw/index.php - recv все нормально возвращает. Каков должен быть запрос чтобы все нормально принималось? (пробывал даже браузерный запрос -> все так же recv == -1)
     
    #1 wolmer, 30 Nov 2010
    Last edited: 2 Dec 2010
  2. rudi

    rudi Active Member

    Joined:
    3 Jun 2010
    Messages:
    487
    Likes Received:
    184
    Reputations:
    5
    попробуй замени
    get_jpg("http://ru.fishki.net/picsw/112010/23/joke.jpg")
    на
    get_jpg("/picsw/112010/23/joke.jpg")
     
  3. wolmer

    wolmer Member

    Joined:
    12 May 2009
    Messages:
    438
    Likes Received:
    97
    Reputations:
    9
    Все так же, recv == -1
     
  4. slesh

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

    Joined:
    5 Mar 2007
    Messages:
    2,702
    Likes Received:
    1,224
    Reputations:
    455
    1) rudi прав. Тыже юзаешь не прокси а сразу запрос на сервак.
    2) strcpy(send_packet, temp); Нафига?? а сразу ты не можешь что-ли отправить temp
    3) если бы заюзал вместо sprintf апишку wsprintfA то онабы заодно тебе и вернула размер результирующей строки не надо былобы потом вычислять длину перед отправкой
    4) while (1) - нафига? если for (;;) более оптимальна
    5) if ((int_temp == 0) || (int_temp == -1)) break; - нафига?
    не проще ли if (int_temp <= 0) break;
    6) fwrite(recv_packet, strlen(recv_packet), 1, h_file); хоть ты и закоментил но всё равно это не правильно. потому что картинка двоичная и по этом strlen не прокатит. да и не нужно это тебе потому что int_temp уже имет размер считанных данных
    7) сокет забываешь проверять при создании
    8) забываешь отрезать HTTP заголовок.


    Насчет проблемы твой. Нафига так сильно привязываться к IP и к имени сайта?
    Проще уже получать IP на основании доменного имени
     
    #4 slesh, 30 Nov 2010
    Last edited: 30 Nov 2010
  5. slesh

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

    Joined:
    5 Mar 2007
    Messages:
    2,702
    Likes Received:
    1,224
    Reputations:
    455
    Вот кусок из одной моей софтины
    Code:
    unsigned int Host2Ip(char * host)
    {
    	struct hostent * p;
    	unsigned int ret;
    
    	ret = inet_addr(host); 
    	
    	if (ret == INADDR_NONE) // if host is not ip
    	{
    		p = gethostbyname(host); // get ip
    		if (p) // if ok
    		{
    			// save ip
    			ret = *(unsigned int*)(p->h_addr);
    		}
    		else // if error
    		{
    			ret = INADDR_NONE;
    		}
    	}
    
    	// return IP or INADDR_NONE
    	return ret;
    }
    
    
    // формат линка site.com/dir/file.ext?param=val
    
    DWORD Download(char* from_link)
    {
    	DWORD ret = 0;
    	SOCKET sock;
    	char * host;
    	char link[256];
    	char header[4096];
    
    	DWORD ip;
    	int len;
    	SOCKADDR_IN sa;
    
    	lstrcpyA(link, from_link);
    	host = link;
    
    	while (*link != 0x00)
    	{
    		if (*link == '/')
    		{
    			*link = 0x00;
    			link++;
    			break;
    		}
    		link++;
    	}
    
    	len = wsprintfA(header, "GET /%s HTTP/1.0\r\nHost: %s\r\nConnection: close\r\n\r\n", link, host);
    
    	sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    	if (sock != INVALID_SOCKET)
    	{
    		ip = Host2Ip(host);
    		if (ip != INADDR_NONE)
    		{
    			sa.sin_addr.S_un.S_addr = ip;
    			sa.sin_family = AF_INET;
    			sa.sin_port = htons(80);
    
    			if (!connect(sock, (SOCKADDR*)&sa, sizeof(sa)))
    			{
    				send(sock, header, len, 0);
    
    				for (;;)
    				{
    					len = recv(sock, header, 4096, 0);
    					
    					if (len <= 0)
    					{
    						break;
    					}
    
    					тут обработка данных
    					ret = 1;
    				}
    			}
    		}
    		closesocket(sock);
    
    	}
    
    	return ret;
    }
    
     
  6. wolmer

    wolmer Member

    Joined:
    12 May 2009
    Messages:
    438
    Likes Received:
    97
    Reputations:
    9
    Помнится как то такой запрос (без строки http...) не прошел (возвращал не 200)

    Спасибо буду знать.

    Всегда задавался вопросом - почему?

    Ну да, не подумал.

    Меня всегда интересовал вопрос - когда сокет может вернуть -1 ? (если же перед этим я к примеру проверил WSAStartup)

    Т.е.? Это по типу твоей функции Host2Ip?
     
  7. rudi

    rudi Active Member

    Joined:
    3 Jun 2010
    Messages:
    487
    Likes Received:
    184
    Reputations:
    5
    Рабочий вариант

    PHP:
    #include "stdafx.h"
    #include <iostream>
    #include <windows.h>
    #include <winsock2.h>



    #define MAXINBUFFLEN 1024 *100
    int get_jpg(char *http_site);

    #pragma comment( lib, "wsock32.lib" )

    int main()
    {
        
    WSADATA ws;
        
    WSAStartup(MAKEWORD(22), &ws);

        

        
    get_jpg("/picsw/112010/23/joke.jpg");

        return 
    0;
    }
    //--------------------------------------------------------------
    int get_jpg(char *http_site)
    {
        
    struct hostent *hp;
        
    struct sockaddr_in serv;
        
    char inbuf[MAXINBUFFLEN], send_packet[4024];
        
    SOCKET sock;
        
    sock socket(AF_INETSOCK_STREAMIPPROTO_TCP);

        
    hp gethostbyname("ru.fishki.net");

        
    serv.sin_family AF_INET;
        
    serv.sin_port htons(80);
        
    memcpy ((char *)&serv.sin_addr,hp->h_addr,hp->h_length);

        
    int con_s connect(sock, (struct sockaddr *) &serv,sizeof(serv));
        
        if (
    con_s != -1)
        {        
            
    sprintf(send_packet"GET %s HTTP/1.0\r\n"
                                 "User-Agent: Opera/10.60 (Windows NT 6.1; U; ru) Presto/2.6.30 Version/10.60\r\n"
                                 "Host: ru.fishki.net\r\n"
                                 "Connection: Close\r\n\r\n"
    http_site);

            
    send(socksend_packetstrlen(send_packet), 0);
            
    int bits =0allbits 0;

            while(
    true)
            {
                    
    bits recv(sock,(inbuf+allbits),20000,0);
                    if(
    bits <= 0){inbuf[allbits] = '\0';  break;};

                    
    allbits += bits;
                    if(
    allbits > (MAXINBUFFLEN 20000))
                       {
    inbuf[allbits] = '\0';  break;}
            }
            
    closesocket(sock);

            if(
    strstr(inbuf,"Content-Type: image/jpeg"))
            {
                    
    char *wp inbuf;
                    
    int totalk 0pos 1length 0;
                    while(
    pos != 0)
                    {
                            
    pos strcspn(wp,"\r\n");
                            
    totalk totalk pos 2;
                            
    wp wp pos;
                    }
                    
    length allbits totalk;
                    
    FILE *fp;
                    
    fp fopen("Image.jpg","wb");
                    for(
    int m 0lengthm++)
                    {
                       
    char s = *wp;
                       
    fputc(s,fp);
                       
    wp++;
                    };

                    
    fclose(fp);
            }                
        }
        
        return 
    0;
    }



     
    2 people like this.
  8. slesh

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

    Joined:
    5 Mar 2007
    Messages:
    2,702
    Likes Received:
    1,224
    Reputations:
    455
    для while (1) без оптимизации да и многи компиляторами генерится код проверки условия 1=1

    mov eax, 1
    test eax, eax
    je метка

    А для for(;;) это не генирится потому что там нет условия для цикла и это считай равноценно

    m1:
    ****
    if (***) goto m2
    **
    goto m1;
    m2:

    Насчет сокетов - редкий но вызывает случай, в частности всякий там софт сторонний который может чтото там хукать итд итп.
    Или когда привышен лими открытых сокетов. Для XP SP2 когдато ловил его ан 170к
     
    1 person likes this.
  9. slesh

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

    Joined:
    5 Mar 2007
    Messages:
    2,702
    Likes Received:
    1,224
    Reputations:
    455
    2 rudi
    1) hp = gethostbyname("ru.fishki.net"); а если глюк днс или еще чегонить и домен не будет найден и вернется NULL то на строчке memcpy ((char *)&serv.sin_addr,hp->h_addr,hp->h_length); будет глюк
    2) на счет считывания ты извратился
    +/-20000 это жесть.
    самый лучший вариант (покрайней мере для меня). Ты никогда не считаешь больше чем буфер потому что recv само прервется когда запрощенное число байт станет <= 0
    Code:
    for (;;)
    {
         len = recv(sock, buf + full_len, max - full_len, 0);
         if (len > 0)
         {
            full_len += len;
           ****
         }
         else
         {
               ***
         }
    }
    
     
  10. wolmer

    wolmer Member

    Joined:
    12 May 2009
    Messages:
    438
    Likes Received:
    97
    Reputations:
    9
    slesh, rudi, спасибо вам, проблему решили.
     
  11. wolmer

    wolmer Member

    Joined:
    12 May 2009
    Messages:
    438
    Likes Received:
    97
    Reputations:
    9
    Никак не пойму в чем была проблема.
    Почему именно gethostbyname спасает в этой ситуации?
    Пробывал под дебагом посмотреть структуру serv.sin_addr. И я увидел что IP'ы совершенно разные (к примеру если сравнивать результат команды ping ru.fishki.net (cmd) & gethostbyname, но почему они разные?).
     
    #11 wolmer, 2 Dec 2010
    Last edited: 2 Dec 2010
  12. Chrome~

    Chrome~ Elder - Старейшина

    Joined:
    13 Dec 2008
    Messages:
    937
    Likes Received:
    162
    Reputations:
    27
    Нет, должны по идеи быть одинаковыми. Может быть ты смотришь не по адресу, который записан в h_addr?
     
  13. wolmer

    wolmer Member

    Joined:
    12 May 2009
    Messages:
    438
    Likes Received:
    97
    Reputations:
    9
    Я ничего не путаю. После строки (см. что прислал rudi):
    memcpy((char *)&server_info.sin_addr,hp->h_addr,hp->h_length);
    я смотрю что находится в server_info.sin_addr.S_un_b,
    и вижу что последняя цифра совершенно другая.
    Пример:
    ping ru.fishki.net говорит нам:
    194.186.88.12

    а server_info.sin_addr.S_un_b это (после gethostbyname естественно):
    194.186.88.3
     
  14. Chrome~

    Chrome~ Elder - Старейшина

    Joined:
    13 Dec 2008
    Messages:
    937
    Likes Received:
    162
    Reputations:
    27
    А, понятно.
    Ну так выполни пару раз в cmd команду ping ru.fishki.net. IP сервера будет иногда менятся (а именно как раз последняя цифра).
     
    #14 Chrome~, 3 Dec 2010
    Last edited: 3 Dec 2010
  15. wolmer

    wolmer Member

    Joined:
    12 May 2009
    Messages:
    438
    Likes Received:
    97
    Reputations:
    9
    Да, и в самом деле так. А почему так происходит?
     
  16. slesh

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

    Joined:
    5 Mar 2007
    Messages:
    2,702
    Likes Received:
    1,224
    Reputations:
    455
    А потому что для A записи в DNS можно прописать несколько IP для домена.
    А если еще и TTL маленький поставить, то еще класс будет. т.е. такая вот хитрая система распределения трафа. Домен один, а там может быть десятки серваков который обрабатывают запросы.