Как задать таймаут для recv

Тема в разделе "WASM.BEGINNERS", создана пользователем _nic, 25 мар 2009.

  1. _nic

    _nic New Member

    Публикаций:
    0
    Регистрация:
    4 фев 2007
    Сообщения:
    372
    Пишу на С ,http+сокеты.Нужно использовать в работе программы прокси.Исходя из того что все паблик прокси УГ.Столкнулся с одной очень болезненной проблемой.После иногда после send recv может ооочень долго ждать входящих данных.Так вот как можно этому делу задать таймаут?Я нагуглил что нужно использовать select,но вот только решений касающихся именно моей проблемы в гугле я не нашол :dntknw: А как работает этот мезанизм до конца немогу понять :dntknw: Вот и мучаюсь вопросами когда вызывать select после send,или вообще перед connect?Надо ли перводить сокет через ioctlsocket в "non-blocking" режим? К сожалению найти специально прокси который бы так фризил неочень просто и поэтому поэкспереминтировать неочень получается :dntknw: Подскажите пожалуйста как это все правильно организовать.
     
  2. s0larian

    s0larian New Member

    Публикаций:
    0
    Регистрация:
    15 июл 2004
    Сообщения:
    489
    Адрес:
    Крыжёпполь
    просто send() это blocking mode. Переведи сокет в non blocking mode, потом send() и потом select(). Последний вернётся когда данные отправлены+приняты или по timeout. Whichever is first.
     
  3. perez

    perez Member

    Публикаций:
    0
    Регистрация:
    25 апр 2005
    Сообщения:
    502
    Адрес:
    Moscow city
    Код (Text):
    1.                         struct timeval timeout; bzero(&timeout, sizeof(timeval));
    2.                         timeout.tv_sec= 1;
    3.                         setsockopt(sclient, SOL_SOCKET, SO_RCVTIMEO, (char*)&timeout, sizeof(timeval));
    [добавлено]

    power1# man setsockopt
    ...........
    Most socket-level options utilize an int argument for optval. For
    setsockopt(), the argument should be non-zero to enable a boolean option,
    or zero if the option is to be disabled. SO_LINGER uses a struct linger
    argument, defined in <sys/socket.h>, which specifies the desired state of
    the option and the linger interval (see below). SO_SNDTIMEO and
    SO_RCVTIMEO use a struct timeval argument, defined in <sys/time.h>.
    ...........
    SO_OOBINLINE enables reception of out-of-band data in band
    SO_SNDBUF set buffer size for output
    SO_RCVBUF set buffer size for input
    SO_SNDLOWAT set minimum count for output
    SO_RCVLOWAT set minimum count for input
    SO_SNDTIMEO set timeout value for output
    SO_RCVTIMEO set timeout value for input
    SO_ACCEPTFILTER set accept filter on listening socket
    SO_NOSIGPIPE controls generation of SIGPIPE for the socket
    SO_TIMESTAMP enables reception of a timestamp with datagrams
    SO_BINTIME enables reception of a timestamp with datagrams
    SO_ACCEPTCONN get listening status of the socket (get only)
    SO_TYPE get the type of the socket (get only)
    SO_ERROR get and clear error on the socket (get only)
     
  4. _nic

    _nic New Member

    Публикаций:
    0
    Регистрация:
    4 фев 2007
    Сообщения:
    372
    Всеравно ничего непонятно :dntknw: Что то должно происходить при таймауте?
    Попытался сделать вот такой эксперимент
    Клиент:
    Код (Text):
    1. void main()
    2. {
    3. char buf[1024]; ULONG ulB=TRUE;fd_set FdSet;
    4. SOCKET s;SOCKADDR_IN adr;WSADATA wsd;
    5. struct timeval Time;int sr=0;
    6. WSAStartup(MAKEWORD(2,0),&wsd);
    7. adr.sin_family=AF_INET;
    8. adr.sin_port=htons(157);
    9. adr.sin_addr.s_addr=inet_addr("127.0.0.1");
    10. s=socket(AF_INET,SOCK_STREAM,0);
    11. getch();
    12. connect(s,(sockaddr*)&adr,sizeof(adr));
    13. ioctlsocket(s,FIONBIO,&ulB);
    14. Time.tv_sec=10;
    15. Time.tv_usec=10*1000000;
    16. FD_ZERO(&FdSet);
    17. FD_SET(s,&FdSet);
    18. for(;;)
    19. {
    20. cin>>buf;
    21. send(s,buf,1024,0);
    22. sr=select(0,NULL,&FdSet,NULL,&Time);
    23. memset(buf,NULL,strlen(buf));
    24. recv(s,buf,1024,0);
    25. if(sr>0){cout<<"timeout"<<endl;}
    26. cout<<buf<<endl;
    27. memset(buf,NULL,strlen(buf));
    28. }
    29. }
    Сервер:
    Код (Text):
    1. void main()
    2. {
    3. char buff[1024];
    4. SOCKET s1,s2;SOCKADDR_IN ladr,cadr;
    5. WSADATA wsd;WSAStartup(MAKEWORD(2,0),&wsd);
    6. ladr.sin_family=AF_INET;
    7. ladr.sin_port=htons(157);
    8. ladr.sin_addr.s_addr=0;
    9. s1=socket(AF_INET,SOCK_STREAM,0);
    10. bind(s1,(sockaddr*)&ladr,sizeof(ladr));
    11. listen(s1,1);
    12. int sz=sizeof(cadr);
    13. s2=accept(s1,(sockaddr*)&cadr,&sz);
    14. for(;;)
    15. {
    16. recv(s2,buff,1024,0);
    17. cout<<buff<<endl;
    18. if(strcmp(buff,"exit")==0){getch();}
    19. send(s2,buff,1024,0);
    20. memset(buff,NULL,strlen(buff));
    21. }
    22. }
    ВОПРОС:как ловить таймаут????
     
  5. s0larian

    s0larian New Member

    Публикаций:
    0
    Регистрация:
    15 июл 2004
    Сообщения:
    489
    Адрес:
    Крыжёпполь
    У тебя много мелких глюков в коде:
    1) что ты посылаешь в ioctlsocket()? Где присвоение?
    2) проверяй что возвращают системные вызовы, пиши в cout
    3) Time = 20с, думаю ты хотел 10
    4) timeout ты пустил в операцию select(), а не в сокет (разные вещи)
    5) после возврата из select() проверь каждый descriptor через FD_ISSET
    6) выведи на экран
     
  6. _nic

    _nic New Member

    Публикаций:
    0
    Регистрация:
    4 фев 2007
    Сообщения:
    372
    Извени я непонимаю ( Что значит: "а не в сокет" ??
    Дескриптор сокета?Для чего?
    Так что же должно произойти с recv по истечению таймаута? Оно должно завершится с кодом ошибки?
     
  7. litrovith

    litrovith Member

    Публикаций:
    0
    Регистрация:
    20 июн 2007
    Сообщения:
    509
    s0larian, не, в данном случае если select() в клиенте, то в него пихается один сокет. FD_ISSET не нужен.

    _nic, по истечению таймаута в хорошем раскладе select вернёт 1, если ничего не будет принято вернёт 0.
     
  8. s0larian

    s0larian New Member

    Публикаций:
    0
    Регистрация:
    15 июл 2004
    Сообщения:
    489
    Адрес:
    Крыжёпполь
    Я имел ввиду sendsockopt(SO_SNDTIMEO), но сейчас проверил доку - эта опция только для blocking sockets. Следовательно делать надо так как ты пробовал - стачала send(), потом select(). Если select() вернёт ноль - значит это timeout. Если 1 - то прверяешь socket-ы с FD_ISSET(). Ессно в случае с одним сокетом это должен быть именно он :)

    С отправкой - та же схема. Если сокетов нескольно - то надо внимательно смотреть что было послано/принято, что осталось, на что уже timeout.
     
  9. litrovith

    litrovith Member

    Публикаций:
    0
    Регистрация:
    20 июн 2007
    Сообщения:
    509
    s0larian, FD_ISSET здесь не нужен )
     
  10. perez

    perez Member

    Публикаций:
    0
    Регистрация:
    25 апр 2005
    Сообщения:
    502
    Адрес:
    Moscow city
    _nic
    Смотри личку
     
  11. _nic

    _nic New Member

    Публикаций:
    0
    Регистрация:
    4 фев 2007
    Сообщения:
    372
    Изменил вот так
    Код (Text):
    1. void main()
    2. {
    3. char buf[1024]; ULONG ulB=TRUE;fd_set FdSet;
    4. SOCKET s;SOCKADDR_IN adr;WSADATA wsd;
    5. struct timeval Time;int sr=1;
    6. WSAStartup(MAKEWORD(2,0),&wsd);
    7. adr.sin_family=AF_INET;
    8. adr.sin_port=htons(157);
    9. adr.sin_addr.s_addr=inet_addr("127.0.0.1");
    10. s=socket(AF_INET,SOCK_STREAM,0);
    11. getch();
    12. connect(s,(sockaddr*)&adr,sizeof(adr));
    13. ioctlsocket(s,FIONBIO,&ulB);
    14. Time.tv_sec=5;
    15. Time.tv_usec=10*1000000;
    16. FD_ZERO(&FdSet);
    17. FD_SET(s,&FdSet);
    18. for(;;)
    19. {
    20. cin>>buf;
    21. send(s,buf,1024,0);
    22. sr=select(0,NULL,&FdSet,NULL,&Time);
    23. memset(buf,NULL,strlen(buf));
    24. if(sr==0){cout<<"timeout"<<endl;}
    25. if(sr!=0)
    26. {
    27. recv(s,buf,1024,0);
    28. cout<<buf<<endl;
    29. memset(buf,NULL,strlen(buf));
    30. }//
    31. }
    32. }
    select 0 невозвращяет сколько не жди :dntknw: Что я не так понял?
    _____________________________________________________
    А все ...Понял...Я не в то место передал параметры select .Вот так select(0,&FdSet,NULL,NULL,&Time) все работает