Проблема с recv в многопоточности

Тема в разделе "WASM.NETWORKS", создана пользователем Kira, 24 янв 2008.

  1. Kira

    Kira New Member

    Публикаций:
    0
    Регистрация:
    24 янв 2008
    Сообщения:
    17
    Здравствуйте, помогите пожалуйста, голову уже сломал
    Нужно из списка доменов грабить главные странички, страничек много и делать надо все быстро поэтому приложение многопоточное. Если обращаться к серверам через 1 поток, то все в порядке. Но при более одного потока при запросе на recv приходит очень много лишнего, то есть при сохрании ответа сервера получается страница и еще часть этой страници... не понимаю почему так происходит.


    Код (Text):
    1.         string message = "GET / HTTP/1.0\r\nHost:"+domain+" \r\n\r\n\r\n"; апрос формируется нормально
    2.         pthread_mutex_lock ( &mutex);        мьютексы от отчаяния включены, помоему они здесь не в кассу.
    3.         char text[1500];                            буфер для приема
    4.         char * request=&message[0];          тк send берет char* перевод сообщения.
    5.         //cout<<request<<endl;                  для проверки
    6.         send(sock, request, strlen(request), 0);      посылаем запрос
    7.     int nsize;                                            
    8.     string page;
    9.     text[0]=0;                                           тоже от отчаяние обнуление буфера
    10.     nsize = recv(sock,text,sizeof(text) -1,0);  получаем первую часть    
    11.     page=page+text;        
    12.         if (check_page(page))                                проверка кода ответа (200 300 301)
    13.         {
    14.           domain=create_folder(domain);                  создается чтото типа файловой базы данных    
    15.           char * ch;
    16.           domain+="index.html";
    17.           ch=&domain[0];
    18.       ofstream out(ch,ios::out);                      поток ввода в файл
    19.           out<<text;                                              кидаем первую часть в файл
    20.       text[0]=0;      
    21.       while (((nsize =  recv(sock,text,sizeof(text) -1,0)))!=0)    получаем ответ и сохраняем его пока не     получем 0 от сервера
    22.           {  
    23.             out<<text;
    24.         text[0]=0; 
    25.           }
    26.           close(sock);
    27.           pthread_mutex_unlock ( &mutex) ;
    28.         }
    Вот такая вот проблема. Не знаю в чем загвоздка по идее сервер долже присылать только один раз аждый пакет потом recv возвращать 0 . но все работает нормально если в одном патоке.
    Помогите плз!
     
  2. MSoft

    MSoft New Member

    Публикаций:
    0
    Регистрация:
    16 дек 2006
    Сообщения:
    2.854
    а ты не пробовал создавать для каждого потока отдельный сокет? иначе, имхо, с синхронизацией жуткие запарки будут
     
  3. Kira

    Kira New Member

    Публикаций:
    0
    Регистрация:
    24 янв 2008
    Сообщения:
    17
    сокет у каждого потока свой естественно, опять же ради перестрахивки дескрипторы раздаются при лоченом мьютексе...
     
  4. MSoft

    MSoft New Member

    Публикаций:
    0
    Регистрация:
    16 дек 2006
    Сообщения:
    2.854
    а ты точно разные хендлы передаешь в recv? иначе это просто мистика какая-то
     
  5. Kira

    Kira New Member

    Публикаций:
    0
    Регистрация:
    24 янв 2008
    Сообщения:
    17
    Код (Text):
    1.                                    
    2. while (1)                             все это находитсся в потоковой функции
    3.   {
    4.     string domain;
    5.     int sock;                          
    6.     pthread_mutex_lock ( &mutex);
    7.     sock = socket(AF_INET, SOCK_STREAM, 0);                              раздача сокета на всякий случай при мьютексе
    8.     pthread_mutex_unlock ( &mutex) ;
    9.     if (!domainStack.empty())                                                      в стеке хранятся имена
    10.     {
    11.       pthread_mutex_lock ( &mutex);
    12.       domain=domainStack.top();
    13.       //cout<<sock<<"   "<<domain<<endl;                                     поток берет одно имя. каждый пото берет разное проверял  
    14.       domainStack.pop();
    15.       pthread_mutex_unlock ( &mutex) ;
    16.       struct sockaddr_in addr;
    17.      
    18.       if(sock < 0)                                                  проверка создания (всегда ок)
    19.       {
    20.         cout<<"error create socket"<<endl;
    21.         totaler++;
    22.         continue;
    23.       }
    24.       addr.sin_family = AF_INET;
    25.       addr.sin_port = htons(80);
    26.       hostent *d_addr;
    27.       char * st= &domain[0];
    28.       d_addr = gethostbyname (st);
    29.       if (d_addr==NULL)                                 собственно, проверка существования днс
    30.       {
    31.     close(sock);
    32.         totaler++;
    33.         continue;  
    34.       }
    35.       addr.sin_addr.s_addr = *((unsigned long *) d_addr->h_addr);
    36.       if(connect(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0)          
    37.       {
    38.         totaler++;
    39.         close(sock);
    40.         continue;
    41.       }
    42.       else
    43.       {                                           а здесь идет предыдущая часть кода
    мистика........ блин, а я так надеялся что я гдето ошибся.....
    Доп.Инфо: При изменении размера буфера text дабавочные лишние куски меняются. Каким должен быть буфер? Может решение здесь?
     
  6. Kira

    Kira New Member

    Публикаций:
    0
    Регистрация:
    24 янв 2008
    Сообщения:
    17
    Для примера пирведу что выдает
    Например для сайта ya.ru выдает
    весть код страницы + еще часть примерно от половины до конца... То есть повторение второго пакета... ингда больше чем одно повторение.
    П.Сэто при одном запросе и чтении в цикле....
     
  7. nester7

    nester7 New Member

    Публикаций:
    0
    Регистрация:
    5 дек 2003
    Сообщения:
    720
    Адрес:
    Russia
    Код (Text):
    1. text[0]=0;
    2. nsize = 0;
    3. while (((nsize +=  recv(sock, text, sizeof(text) -1, 0))) != 0)
    4. {
    5.     text[nsize] = '\0';
    6.     out<<text;
    7.     text[0]=0; 
    8. }
    ?
     
  8. nester7

    nester7 New Member

    Публикаций:
    0
    Регистрация:
    5 дек 2003
    Сообщения:
    720
    Адрес:
    Russia
    Нужно только цикл переделать, чтобы nsize обновлялось и проверялось условие
    Вроде этого:

    Код (Text):
    1. nrecvd = 0;
    2. nsize = 0;
    3. while (1)
    4. {
    5.     nrecvd = recv(sock, &text[nsize], sizeof(text) - nsize -1, 0));
    6.     if (nrecvd == 0) {
    7.         text[nsize] = '\0';
    8.         out bla-bla;
    9.         break;
    10.     }
    11.  
    12.     nsize += nrecvd;
    13. }
     
  9. nester7

    nester7 New Member

    Публикаций:
    0
    Регистрация:
    5 дек 2003
    Сообщения:
    720
    Адрес:
    Russia
    Что-то я тут сморозил спросони :)
    У тебя в принципе тоже самое, просто без
    накопления в буфере.
     
  10. Kira

    Kira New Member

    Публикаций:
    0
    Регистрация:
    24 янв 2008
    Сообщения:
    17
    ну да nsize это код ответа.
    он ДОЛЖЕН возврящать 0 если сервер закрыл соединение.
    но что то хдесь не так и 0 возвращаетсяя (тк файл всетаки сохраняется) позже
    1. Файл сохраняется => сервер отвечает о закрытии соединения.
    2 Буфер обнуляется после кажого ответа
    3. Сокет каждвм потоком получается свой( проверенно и невозможно вследствии закрытого мьютекса при получении сокета)
    4. Сервер должен по протоколу HTTP 1.0 посылать не разнопотоковый а поток из последовательных сообщений.
    5. Приходит несколько последних пакетов..............
    ПОЧЕМУ?
     
  11. nester7

    nester7 New Member

    Публикаций:
    0
    Регистрация:
    5 дек 2003
    Сообщения:
    720
    Адрес:
    Russia
    А tcpdump(или Ethereal) что говорит, тоже дубли показывает?
     
  12. Kira

    Kira New Member

    Публикаций:
    0
    Регистрация:
    24 янв 2008
    Сообщения:
    17
    ??? понятия не имею о чем ты говоришь))
    Пробывал смотреть что приходит только через cout
    там тоже дубли причем при одинаковом буфере одинаковые.
    Обьясни плз как и где смотреть через tcpdump(или Ethereal)
    сорри за нубскость, но я реально с этим не сталкивася никогда)
     
  13. Kira

    Kira New Member

    Публикаций:
    0
    Регистрация:
    24 янв 2008
    Сообщения:
    17
    ПС при желании могу оставить весь код.
    он не сложный но довольно длинный
    и даже без классов)))
     
  14. Kira

    Kira New Member

    Публикаций:
    0
    Регистрация:
    24 янв 2008
    Сообщения:
    17
    Так... почитал вопрос на форуме "Длинна HTTP сообщения?"
    обьясниете ктонибудь если я в запросе пишу connectin:close мне присылается один пакет или се покеты до конца?
    может в этом загвоздка?
     
  15. nester7

    nester7 New Member

    Публикаций:
    0
    Регистрация:
    5 дек 2003
    Сообщения:
    720
    Адрес:
    Russia
    Почитай мануал к tcpdump, и с ним смотри что и куда делает твоя прога.

    Примерно вот так:
    tcpdump -i 3 -n -nn -s 512 port 80

    Но это под Win, в *nix параметры могут немного отличаться, в первую очередь
    именем интерфейса. Сделай ifconfig и посмотри как у тебя называется
    интерфейс, через который ты в интернет выходишь (к примеру, eth0 для Linux или rl0 - для FreeBSD),
    а потом делай
    tcpdump -i eth0 -n -nn -s 512 port 80

    Подробнее читай мануал (man tcpdump или на opennet.ru сходи, там, кажется, есть русский)


    [added]
    Параметр пролюбил.
    tcpdump -i eth0 -n -nn -X -s 512 port 80
     
  16. Kira

    Kira New Member

    Публикаций:
    0
    Регистрация:
    24 янв 2008
    Сообщения:
    17
    Проблема исправлена
    nester7 спасибо
    На интерфейс приходило все нормально, вся загвоздка заключалась в том что буфер text накапливал куски, и когда приходил последний кусок в буфере (даже при его обнулении, чего кстати не происходило) содержался кусок конца предыдущей части.
    Обнуление не проходит
    пробывал
    text[0]='\0';
    chat text=new text[1024];
    единственное что помогло это уменьшение буфера до 20 (причем программа стала значительно шустрее и
    ручное обнуление
    text[0]='\0';
    text[1]='\0';
    text[2]='\0';
    и тд
    Может кто обьяснит как его обнулить?
    Зарание благодарен
    Всем спасибо за ответы)
     
  17. nester7

    nester7 New Member

    Публикаций:
    0
    Регистрация:
    5 дек 2003
    Сообщения:
    720
    Адрес:
    Russia
    Где-то бага, его не нужно полностью обнулять :)
    Но можно тупо - перед циклом получения занулить буфер целиком через memset(buf, 0, size).
     
  18. nester7

    nester7 New Member

    Публикаций:
    0
    Регистрация:
    5 дек 2003
    Сообщения:
    720
    Адрес:
    Russia
    Вот так должно работать:
    Код (Text):
    1. while (((nsize =  recv(sock,text,sizeof(text) -1,0)))!=0)
    2. {
    3.     text[nsize] = 0;
    4.     out<<text;
    5. }
     
  19. Kira

    Kira New Member

    Публикаций:
    0
    Регистрация:
    24 янв 2008
    Сообщения:
    17
    Огромное спасибо, извиняюсь уезжал надолго ( жил без нета 6 дней!))) )
    А представленный код не работает ( и кстате не правильный)
    memset не пробывал еще но думаю и без него обойдусь.
    Еще раз спасибо
     
  20. Gordon

    Gordon New Member

    Публикаций:
    0
    Регистрация:
    21 апр 2005
    Сообщения:
    21
    Адрес:
    Russia
    Вообще то нелохо было бы обрабатывать код ошибки от recv, потому как при этом данный код ведет себя сильно некорретно.