Загрузка Web-страницы с использованием сокетов

Тема в разделе "WASM.NETWORKS", создана пользователем simnet_, 2 сен 2009.

  1. simnet_

    simnet_ New Member

    Публикаций:
    0
    Регистрация:
    18 дек 2007
    Сообщения:
    109
    С сокетами только начал разбираться, и возникла проблема, что клиент иногда не загружает полностью запрошенную Web-страницу. Код примерно такой:

    Код (Text):
    1.    
    2. #include <sys/socket.h>
    3. #include <sys/types.h>
    4. #include <sys/un.h>
    5. #include <unistd.h>
    6. #include <stdio.h>
    7. #include <netinet/in.h>
    8. #include <netdb.h>
    9. #include <stdlib.h>
    10. #include <string.h>
    11. #include <arpa/inet.h>
    12.  
    13. #define HOSTNAME "philka.ru"
    14.     int ret = 0, count = 0;
    15.     int sock = socket(AF_INET, SOCK_STREAM, 0);
    16.  
    17.     struct sockaddr_in addr;
    18.     memset(&addr, 0, sizeof(struct sockaddr));
    19.     addr.sin_family = AF_INET;
    20.     addr.sin_port = htons(80);
    21.     struct hostent *resaddrs=gethostbyname(HOSTNAME);
    22.     if (resaddrs==NULL) {
    23.         //Address resolution error
    24.         printf("address not found\n");
    25.     }
    26.     addr.sin_addr = *(in_addr*)resaddrs->h_addr_list[0];
    27.     ret = connect(sock, (struct sockaddr*)&addr, sizeof(struct sockaddr));
    28.     if (ret==-1) {
    29.         //error creating connecting
    30.         printf("Connect() error\n");
    31.         return -1;
    32.     }
    33.  
    34.     char buf[10000];
    35.     sprintf(buf, "%s%s%s%s%s%s%s%s",
    36.         "GET /news.php HTTP/1.1\x0d\x0a",
    37.         "Accept: */*\x0d\x0a",
    38.         "Accept-Language: ru\x0d\x0a",
    39.         "Accept-Encoding: gzip, deflate\x0d\x0a",
    40.         "User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 2.0.50727; .NET CLR 3.0.04506.648; .NET CLR 3.5.21022)\x0d\x0a"
    41.         "Host: ", HOSTNAME, "\x0d\x0a",
    42.         "Connection: Keep-Alive\x0d\x0a\x0d\x0a"
    43.         );
    44.  
    45.    printf(buf);  //Что мы отправляем
    46.     count = write(sock, buf, strlen(buf));
    47.     printf("\n%i bytes were written", count);
    48.     while(1) {  //читаем пока есть что читать (Web-сервер может возвращать данные по кускам, в несколько приемов)
    49.         count = read(sock, buf, 10000);
    50.         if (count==0) return 0;
    51.         printf(buf);
    52.     }
    В результате - в консоли печатается только часть текста, хотя счетчики count в сумме дают значения поля заголовка Content-Length, Wireshark показывает, что HTML код передается полностью. Почему он не считывается из буфера до конца? Такое случается со многими сайтами

    ОС Linux, gcc, оболочка xterm
     
  2. simnet_

    simnet_ New Member

    Публикаций:
    0
    Регистрация:
    18 дек 2007
    Сообщения:
    109
    и еще, количество выводимой в консоль информации зависит от значения поля Connection: Keep-Alive или Close. Почему так?

    Спасибо
     
  3. r90

    r90 New Member

    Публикаций:
    0
    Регистрация:
    26 ноя 2005
    Сообщения:
    898
    Код (Text):
    1. count = read(sock, buf, 10000);
    2. if (count==0) return 0;
    3. printf(buf);
    count может быть равен нулю, если выполнение read было прервано сигналом. Правильно будет так:
    Код (Text):
    1. while (count > 0) {
    2.     do {
    3.         count = read (sock, buf, sizeof (buf) - 1);
    4.     } while (count < 0 && errno == EINTR);
    5.     if (count < 0) {
    6.          perror ("read");
    7.          exit (1);
    8.     }
    9.     if (count > 0) {
    10.         buf[count] = '\0';
    11.         printf (buf);
    12.     }
    13. }
     
  4. r90

    r90 New Member

    Публикаций:
    0
    Регистрация:
    26 ноя 2005
    Сообщения:
    898
    эхм. код вроде правильный, а вот утверждение что если errno == EINTR то count == 0 неверно. count < 0 в случае прерывания сигналом. Кстати твой код будет делать что-то странное в этом случае.
     
  5. simnet_

    simnet_ New Member

    Публикаций:
    0
    Регистрация:
    18 дек 2007
    Сообщения:
    109
    r90
    Большое спасибо за ответ, а нету функций "безопасных" относительно других сигналов? напрмер, блокирующие другие сигналы на время своего исполнения? Или не реагирующие таким образом? Кстати, почему разработчики решили зделать возврат 0, вместо того чтобы продолжить чтение?
    А в Windows нужно предусматривать такую ситуацию?
     
  6. simnet_

    simnet_ New Member

    Публикаций:
    0
    Регистрация:
    18 дек 2007
    Сообщения:
    109
    Вот странно, теперь вызов read() блокируется, прочитав почти весь файл - кроме последней строки.
    Хотя с вашим вариантом читает намного больше, чем в моем случае
     
  7. litrovith

    litrovith Member

    Публикаций:
    0
    Регистрация:
    20 июн 2007
    Сообщения:
    509
    я в си не понимэ, но разве это:
    Код (Text):
    1. ....
    2. printf("\n%i bytes were written", count);
    3.     while(1) {...
    правильно? )
     
  8. megaaa

    megaaa New Member

    Публикаций:
    0
    Регистрация:
    29 май 2009
    Сообщения:
    51
    а что за read/write, не проще заюзать send/recv или это не windows?)
    я бы сделал так:

    Код (Text):
    1.         while ( rcv = recv( Socket, RecvBuffer + recved,  256, 0 )  )
    2.     {
    3.         recved += rcv;
    4.     }
    5.  
    6.     RecvBuffer[recved] = '\0';
    ну и нужно учесть что буффера выделенного тобою для скачки страницы может не хватить.

    и еще тут:
    Код (Text):
    1.     while(1) {  //читаем пока есть что читать (Web-сервер может возвращать данные по кускам, в несколько приемов)
    2.         count = read(sock, buf, 10000);
    3.         if (count==0) return 0;
    4.         printf(buf);
    5.     }
    после printf, надо бы буффер мемсетом зачистить)
     
  9. r90

    r90 New Member

    Публикаций:
    0
    Регистрация:
    26 ноя 2005
    Сообщения:
    898
    simnet_
    Вероятно из-за: Connection: Keep-Alive. Выдери из ответа сервера Content-Length, считай принятые байты и не читай больше чем надо прочитать.