Форум программистов, компьютерный форум, киберфорум
C++: Сети
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
 
Рейтинг 4.93/41: Рейтинг темы: голосов - 41, средняя оценка - 4.93
Эксперт С++
 Аватар для Avazart
8484 / 6151 / 615
Регистрация: 10.12.2010
Сообщений: 28,683
Записей в блоге: 30

Реализовать таймаут

16.11.2012, 19:47. Показов 8340. Ответов 29
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Допустим есть пишем класс обвертку над winsocks.

Как реализовать таймаут соединения.

К примеру есть метод класса, при вызове которого должно быть отправлено сообщение на сервер и ожидатся какое то время ответ с него, если нет, то возвращение значения или выбрасывается исключения.

C++
1
2
3
4
5
6
7
8
9
10
bool some_class::some_method(std::string msg, std::string& result)
{
  // код отправки msg
    if( ! Ok )  return false;
 
  // код приема в result , и если не удалось принять Ok = 0;
  if( ! Ok )  return false;
 
  return true; 
}
Вообще и без многопоточности подобно Indy - компонентам
0
Programming
Эксперт
39485 / 9562 / 3019
Регистрация: 12.04.2006
Сообщений: 41,671
Блог
16.11.2012, 19:47
Ответы с готовыми решениями:

Таймаут?
Доброго времени суток! Подскажите пожалуйста что использовать чтобы реализовать описанное ниже? Каждую, например, секунду...

Синхронные сокеты и таймаут
Решил соорудить небольшой наколенный многопоточный клиент dht . Есть некоторые вопросы по сокетам и гугол как-то больше молчит . ...

Как организовать таймаут?
Как сделать так чтобы, допустим клиент отправил серверу данные по TCP. Сервер принял и отправляет ответ клиенту. И пока клиент не прочтет...

29
204 / 205 / 16
Регистрация: 06.08.2011
Сообщений: 600
Записей в блоге: 1
17.11.2012, 20:48
Ожидай данные select'ом либо IOCP. Закончится время - кидай исключение.
0
Эксперт С++
 Аватар для Avazart
8484 / 6151 / 615
Регистрация: 10.12.2010
Сообщений: 28,683
Записей в блоге: 30
17.11.2012, 20:50  [ТС]
А пример можно или псевдокод?

select вроде только проверяет наличия соединения или я ошибаюсь?
0
204 / 205 / 16
Регистрация: 06.08.2011
Сообщений: 600
Записей в блоге: 1
17.11.2012, 20:59
select проверяет готовность сокета. К соединению или чтению не важно.
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
       bool wait_for_read( DWORD timeout = INFINITE ) const {
 
            fd_set recv_set = {0};
 
            timeval tv = {0};
            timeval *tvp;
 
            if (timeout == INFINITE) {
                tvp = NULL;
            } else {
                tv.tv_sec = timeout / 1000;
                tv.tv_usec = (timeout % 1000) * 1000;
                tvp = &tv;
            }
            FD_SET(sock, &recv_set);
            int res = 0;
            res = ::select(sock + 1, // useless in windows
                            &recv_set, NULL, NULL, tvp);
            // res == -1 -- throw ... 
            return (res != 0);
        }
1
Эксперт С++
 Аватар для Avazart
8484 / 6151 / 615
Регистрация: 10.12.2010
Сообщений: 28,683
Записей в блоге: 30
17.11.2012, 21:28  [ТС]
Ну так если сначала проверим и сразу читаем, то нормально будет ?
Теоретически ведь соединение может упасть в промежутке между этими действиями- это меня заботит.

Или я неправильно понимаю- select говорит о уже принятой информации и готовой к чтению ?

IOCP как понимаю для не блокируемого режима

Добавлено через 20 минут
С помощью функции select и этого набора макросов, мы можем проверять конечное множество сокетов на готовность к считыванию/отсылке данных, выполнения connect, на предмет входящих соединений, наличия OOB сообщений и т.п. На данном этапе нас интересует проверка сокета на возможность считывания данных, поэтому пока ограничимся самым простым вызовом select. Для этого нам необходимо поместить наш сокет в множество на которое будет указывать readfds (в примере это read_s), задать timeout и выполнить select.
http://club.shelek.ru/viewart.php?id=37

Здесь имеется ввиду готовность нашего клиент-сокета или сокет-сервера на той стороне соединения ?
Вот что мне непонятно...
0
1259 / 650 / 44
Регистрация: 06.02.2011
Сообщений: 1,654
17.11.2012, 21:49
Для блокируемых сокетов иногда бывает проще поставить SO_(RCV|SND)TIMEO
0
Эксперт С++
 Аватар для Avazart
8484 / 6151 / 615
Регистрация: 10.12.2010
Сообщений: 28,683
Записей в блоге: 30
17.11.2012, 21:51  [ТС]
g_u_e_s_t, А по подобнее ?
0
1259 / 650 / 44
Регистрация: 06.02.2011
Сообщений: 1,654
17.11.2012, 21:56
Посредством setsockopt() выставляем максимальное время ожидания для операций чтения/записи на сокете. Т.е. например recv() будет ждать данных не "вечно" а N секунд.
0
Эксперт С++
 Аватар для Avazart
8484 / 6151 / 615
Регистрация: 10.12.2010
Сообщений: 28,683
Записей в блоге: 30
17.11.2012, 22:31  [ТС]
Т.е имеется ввиду SO_RCVTIMEO и SO_SNDTIMEO
SO_RCVTIMEO DWORD Sets the timeout, in milliseconds, for blocking receive calls.
SO_SNDTIMEO DWORD The timeout, in milliseconds, for blocking send calls.
http://msdn.microsoft.com/en-u... 85%29.aspx

Как я понимаю в случае таймаута будет возвращено SOCKET_ERROR ?
0
1259 / 650 / 44
Регистрация: 06.02.2011
Сообщений: 1,654
17.11.2012, 22:47
Там же все написано...
0
Эксперт С++
 Аватар для Avazart
8484 / 6151 / 615
Регистрация: 10.12.2010
Сообщений: 28,683
Записей в блоге: 30
18.11.2012, 03:10  [ТС]
Ну читаю
SO_RCVTIMEO and SO_SNDTIMEO

When using the recv function, if no data arrives during the period specified in SO_RCVTIMEO, the recv function completes. In Windows versions prior to Windows 2000, any data received subsequently fails with WSAETIMEDOUT. In Windows 2000 and later, if no data arrives within the period specified in SO_RCVTIMEO, the recv function returns WSAETIMEDOUT, and if data is received, recv returns SUCCESS.
Только что-то я не пойму это вроде касается level = NSPROTO_IPX, в IPPROTO_TCP вроде ничего не сказано про SO_RCVTIMEO.
Или это лишь уровень на котором задается поведение?

Добавлено через 7 минут
Не туда глянул ....

Добавлено через 13 минут
Как я понимаю приблизительно так должно выглядеть

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
DWORD interval = 1000; // мс
int size = sizeof (DWORD);
//....
ListenSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
//...
iResult = setsockopt(ListenSocket, SOL_SOCKET, SO_RCVTIMEO,  (char *)&interval,size);
 
if (iResult == SOCKET_ERROR)   
   {
       wprintf(L"setsockopt for SO_KEEPALIVE failed with error: %u\n", WSAGetLastError());
   } 
else
      wprintf(L"SO_RCVTIMEO: ON\n");
 
 
iResult = setsockopt(ListenSocket, SOL_SOCKET, SO_SNDTIMEO,  (char *)&interval, size);
 
if (iResult == SOCKET_ERROR)   
   {
       wprintf(L"setsockopt for SO_SNDTIMEO failed with error: %u\n", WSAGetLastError());
   } 
else
      wprintf(L"SO_SNDTIMEO: ON\n");
Добавлено через 2 часа 23 минуты
В общем теперь пытаюсь реализовать
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
//---------------------------------------------------------------------------
bool client_t::connect()
{
    _socket= ::socket(AF_INET,SOCK_STREAM,0);
    if(_socket==INVALID_SOCKET) return false;
 
    if( ::connect(_socket, (sockaddr*)&_addr, sizeof(_addr) ) ) return false;
    else
        {
            #ifdef MyDebug
                std::cerr<<"[Debug] "<<"Соединение установлено."<<std::endl;
            #endif
        }
     /*
    if(setsockopt( _socket, SOL_SOCKET,
                                 SO_RCVTIMEO,
                                 (char *)&_timeout,
                                 sizeof(_timeout) ) == SOCKET_ERROR) return false;
 
    if(setsockopt( _socket, SOL_SOCKET,
                                 SO_SNDTIMEO,
                                 (char *)&_timeout,
                                 sizeof(_timeout) ) == SOCKET_ERROR) return false;
     */
return true;
}
//---------------------------------------------------------------------------
bool client_t::send(std::string cmd)
{
    int length = ::send(_socket, cmd.c_str(), cmd.length(), NULL);
    return length != SOCKET_ERROR;
}
//---------------------------------------------------------------------------
bool client_t::receive(std::string& response)
{
response.clear();
int length= 0;
 
do
    {
        //memset(_buff,'\0',MAX_LENGTH);
        length= ::recv( _socket, _buff, MAX_LENGTH, NULL);
        if(length == SOCKET_ERROR)
            {
             #ifdef MyDebug
                    std::cerr<<"[Debug] "<<"Ошибка чтения."<<std::endl;
             #endif
             return false;
            }
        #ifdef MyDebug
                    std::cerr<<"[Debug] "<<"Принято "<<length<<" Байт"<<std::endl;
        #endif
        response+= std::string(_buff, length) ;
    }
while( length!=0 );
 
return true;
}
//---------------------------------------------------------------------------
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
//---------------------------------------------------------------------------
int main(int argc, char* argv[])
{
system("chcp 1251");
system("color 0a");
 
using namespace std;
 
my::client_t client1;
 
client1.set_port(110);
if(! client1.set_addr("pop.yandex.ru") ) client1.get_error();
 
if(! client1.connect() ) client1.get_error();
 
std::string response;
if( ! client1.receive(response) ) client1.get_error();
cout<< response;
 
 
system("pause");
return 0;
}
//---------------------------------------------------------------------------
Получаю
Bash
1
2
3
4
5
6
7
8
Текущая кодовая страница: 1251
[Debug] WSA успешно запущена
[Debug] Создан клиент, количество клиентов 1
[Debug] Соединение установлено.
[Debug] Принято 38 Байт   // тут задержка
[Debug] Принято 0 Байт
+OK POP Ya! v1.0.0na@10 6jUYG7JN6qM1
Для продолжения нажмите любую клавишу . . .
Если раскомментировать код с setsockopt получаю ошибку
Bash
1
2
3
4
5
6
7
8
9
10
Текущая кодовая страница: 1251
[Debug] WSA успешно запущена
[Debug] Создан клиент, количество клиентов 1
[Debug] Соединение установлено.
[Debug] Принято 37 Байт // Задержка на таймаут
[Debug] Ошибка чтения.
Error #10060 Попытка установить соединение был  // ... бла-бла  - вообщем таймаут
 
+OK POP Ya! v1.0.0na@4 isU07sn5IOs1
Для продолжения нажмите любую клавишу . . .
До этого код работал на колбеке где получение было порциями. А как тут понять что прием закончен ?

Если таймауты не устанавливать, когда прием закончен recv возвращает 0.
А если установлены - ошибку.
0
1259 / 650 / 44
Регистрация: 06.02.2011
Сообщений: 1,654
18.11.2012, 10:21
Цитата Сообщение от Avazart Посмотреть сообщение
Как я понимаю приблизительно так должно выглядеть
Честно говоря я не уверен, что в Виндах есть какой-то смысл в этих опциях для listen сокета.
Цитата Сообщение от Avazart Посмотреть сообщение
До этого код работал на колбеке где получение было порциями. А как тут понять что прием закончен ?
Точно так же, ничего не поменялось. Можете сказать серверу quit и убедиться, что после "+ok" recv вернет вам 0.
Цитата Сообщение от Avazart Посмотреть сообщение
Если таймауты не устанавливать, когда прием закончен recv возвращает 0.
А если установлены - ошибку.
Просто таймаут случается раньше чем сервер закрывает сокет.

Если Ваша цель pop3 клиент, то лучше начать не с сокетов и тем более таймаутов, а с реализации FSM.
0
Эксперт С++
 Аватар для Avazart
8484 / 6151 / 615
Регистрация: 10.12.2010
Сообщений: 28,683
Записей в блоге: 30
18.11.2012, 15:48  [ТС]
Цитата Сообщение от g_u_e_s_t Посмотреть сообщение
Просто таймаут случается раньше чем сервер закрывает сокет.
Оуу какой закрывать ? Я ему не говорил закрывать соединение...

Или я что-то не понимаю ? recv возвращает 0 только при закрытие соединения ?

Добавлено через 6 минут
Цитата Сообщение от g_u_e_s_t Посмотреть сообщение
Если Ваша цель pop3 клиент, то лучше начать не с сокетов и тем более таймаутов, а с реализации FSM.
Не уверен в том что вы понимаете под FSM, то логичнее начинать снизу вверх а не на оборот.

А задача понять как приблизительно может работать Indy.

Добавлено через 40 секунд
recv возвращает 0 только при закрытие соединения ?
А как тут понять что прием закончен ?
0
1259 / 650 / 44
Регистрация: 06.02.2011
Сообщений: 1,654
18.11.2012, 16:45
Цитата Сообщение от Avazart Посмотреть сообщение
Я ему не говорил закрывать соединение...
Ну вот захотел и закрыл, Ваше "я не говорил" удаленной стороне вообщем случае по барабану... что хочет то и делает
Цитата Сообщение от Avazart Посмотреть сообщение
ли я что-то не понимаю ?
Похоже да.
Цитата Сообщение от Avazart Посмотреть сообщение
recv возвращает 0 только при закрытие соединения ?
Для SOCK_STREAM есть еще вариант recv(,,0,) при котором некоторые системы (например оригинальный BSD стэк) возвращают 0, но это не Ваш случай.
Цитата Сообщение от Avazart Посмотреть сообщение
Не уверен в том что вы понимаете под FSM,
Машина состояний протокола.
Цитата Сообщение от Avazart Посмотреть сообщение
о логичнее начинать снизу вверх а не на оборот.
Угу, заметно.
Цитата Сообщение от Avazart Посмотреть сообщение
А как тут понять что прием закончен ?
Где тут? Я совершенно без понятия, кто такой/ая Ваша Indy...
Если Вы о своем коде с зачатками pop3, то смотреть, что именно ответил сервер после каждого успешного recv().
0
Эксперт С++
 Аватар для Avazart
8484 / 6151 / 615
Регистрация: 10.12.2010
Сообщений: 28,683
Записей в блоге: 30
18.11.2012, 17:08  [ТС]
Цитата Сообщение от g_u_e_s_t Посмотреть сообщение
Если Вы о своем коде с зачатками pop3, то смотреть, что именно ответил сервер после каждого успешного recv().
POP3 лишь пример обмена командами.

Ну так, как я узнаю что ответил полностью, а главное что он закончил отвечать?

Добавлено через 3 минуты
Сервер то может отвечать порциями...
0
1259 / 650 / 44
Регистрация: 06.02.2011
Сообщений: 1,654
18.11.2012, 17:25
Цитата Сообщение от Avazart Посмотреть сообщение
POP3 лишь пример обмена командами.
Дык... Вы определитесь, _что_ именно Вы делаете...
Если _универсальные_ обертки над send/recv это одно и тут как конец приема/передачи можно рассматривать только ошибку или закрытый сокет,
Прием/отправку POP3 это другое (не кто не запрещает использовать ф-ции написанные в 1м случае) и тут в дополнение к общему случаю, как конец приема ответа на команду/приветствие сервера нужно рассматривать в контексте конкретной фазы протокола. Например если после успешной авторизации на NOOP сервер Вам ответит, что-то отличное от "+OK...\n" остается только выругаться и разорвать соединение.
тоже SMTP - третье, HTPP - четвертое
и т.д. и тп.
1
Эксперт С++
 Аватар для Avazart
8484 / 6151 / 615
Регистрация: 10.12.2010
Сообщений: 28,683
Записей в блоге: 30
18.11.2012, 17:32  [ТС]
Ну теперь более или менее понятно нужно отдельно смотреть по каждому протоколу и по ответу... универсально не получится...
На первый взгляд вроде бы всё нормально. Но это не так! В вызове функции recv присутствует параметр MAX_PACKET_SIZE, который определяет длину буфера приёма данных. То есть, Winsock протоколы (TCP/UDP) могут "отправить" пакет размером и 65535 байт. Однако, реальный размер IP пакета, может быть меньше передаваемых данных для конкретного типа сети ( величина MTU - размер наибольшего допустимого кадра в локальной сети или глобальном канале) и поэтому данные фрагментируются (кто хочет - смотрит описание TCP/IP протокола, мы не будем пока углубляться в описание "железного" уровня сети). При этом, фрагментированные данные могут идти с задержками. Какое отношение имеет данная особенность к нашей программе? Всё очень просто. Если мы запросим у удалённого Web-сервера не такой маленький кусочек HTML-кода, как в нашем примере, а немного побольше, то мы получим только первую порцию данных от сервера. Остальная часть данных будет, скорее всего, утеряна. Выход из данного положения очень прост. Он основан на знании принципа работы HTTP и TCP/IP протоколов, плюс некоторых особенностей Winsock. В нашем случае Web-сервер, передав последнюю порцию данных, закроет соединение. А функция recv в таком случае, после получения последнего фрагмента данных, возвращает ноль. Вывод напрашивается сам: мы должны читать входящие данные до тех пор, пока функция recv не вернет ноль.
http://club.shelek.ru/viewart.php?id=37

Вот только HTTP не всегда закрывает соединение...
Тут по заголовку походу надо определять...
0
1259 / 650 / 44
Регистрация: 06.02.2011
Сообщений: 1,654
18.11.2012, 17:44
цитата жжот. Человек просто не понимает о чем пишет... Набор умных и правильных слов, но вместе - полный бред.
0
Эксперт С++
 Аватар для Avazart
8484 / 6151 / 615
Регистрация: 10.12.2010
Сообщений: 28,683
Записей в блоге: 30
18.11.2012, 18:00  [ТС]
Ну б сказал нет однозначности...

Правильно ли я понимаю?

1. Если размер буфера меньше размера "пришедшей информации", то recv вызывается несколько раз.
2. Следовательно надо или четко указывать длину буфера так что бы прием шел в один recv, либо
обрабатывать инфу в каждом recv (с анализом заголовка/ответа протокола)

???
0
1259 / 650 / 44
Регистрация: 06.02.2011
Сообщений: 1,654
18.11.2012, 18:25
Есть задачи когда нужно смотреть куда-то в полученные (возможно раньше) данные, есть где достаточно "не ошибки" в ф-ции передачи... Т.е. это все абстрактные рассуждения ни о чем.
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
inter-admin
Эксперт
29715 / 6470 / 2152
Регистрация: 06.03.2009
Сообщений: 28,500
Блог
18.11.2012, 18:25
Помогаю со студенческими работами здесь

TCP SO_KEEPALIVE и таймаут на прием
Есть клиент, должен посылать несколько запросов подряд, поставил SO_SND+RCVTIMEO, решил добавить ему keep-alive, но с этим проблема: send()...

Работа с UDP, таймаут для setsockopt
Доброго времни суток. Пользуюсь Windows 8.1, Visual Studio 2013, C++. Пытаюсь использовать setsockopt для установки таймаута у recvfrom, в...

Реализовать таймаут PHP pthreads
&lt;?php /** * Author: Abu Ashraf Masnun * URL: http://masnun.me */ //define(&quot;TMT&quot;,3); class WorkerThreads extends Thread ...

Как реализовать таймаут ожидания интента?
у меня есть приложение, пишет кое что на карту mifare classic проблема в том, что все проиходит очень быстро, и прикладывая карту, я...

Как реализовать таймаут на поиск элемента?
Доброго времени суток всем читающим! Помогите, пожалуйста, реализовать таймаут на C#. Занимаюсь задачей автоматизации десктопного...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
20
Ответ Создать тему
Новые блоги и статьи
PhpStorm 2025.3: WSL Terminal всегда стартует в ~
and_y87 14.12.2025
PhpStorm 2025. 3: WSL Terminal всегда стартует в ~ (home), игнорируя директорию проекта Симптом: После обновления до PhpStorm 2025. 3 встроенный терминал WSL открывается в домашней директории. . .
Access
VikBal 11.12.2025
Помогите пожалуйста !! Как объединить 2 одинаковые БД Access с разными данными.
Новый ноутбук
volvo 07.12.2025
Всем привет. По скидке в "черную пятницу" взял себе новый ноутбук Lenovo ThinkBook 16 G7 на Амазоне: Ryzen 5 7533HS 64 Gb DDR5 1Tb NVMe 16" Full HD Display Win11 Pro
Музыка, написанная Искусственным Интеллектом
volvo 04.12.2025
Всем привет. Некоторое время назад меня заинтересовало, что уже умеет ИИ в плане написания музыки для песен, и, собственно, исполнения этих самых песен. Стихов у нас много, уже вышли 4 книги, еще 3. . .
От async/await к виртуальным потокам в Python
IndentationError 23.11.2025
Армин Ронахер поставил под сомнение async/ await. Создатель Flask заявляет: цветные функции - провал, виртуальные потоки - решение. Не threading-динозавры, а новое поколение лёгких потоков. Откат?. . .
Поиск "дружественных имён" СОМ портов
Argus19 22.11.2025
Поиск "дружественных имён" СОМ портов На странице: https:/ / norseev. ru/ 2018/ 01/ 04/ comportlist_windows/ нашёл схожую тему. Там приведён код на С++, который показывает только имена СОМ портов, типа,. . .
Сколько Государство потратило денег на меня, обеспечивая инсулином.
Programma_Boinc 20.11.2025
Сколько Государство потратило денег на меня, обеспечивая инсулином. Вот решила сделать интересный приблизительный подсчет, сколько государство потратило на меня денег на покупку инсулинов. . . .
Ломающие изменения в C#.NStar Alpha
Etyuhibosecyu 20.11.2025
Уже можно не только тестировать, но и пользоваться C#. NStar - писать оконные приложения, содержащие надписи, кнопки, текстовые поля и даже изображения, например, моя игра "Три в ряд" написана на этом. . .
Мысли в слух
kumehtar 18.11.2025
Кстати, совсем недавно имел разговор на тему медитаций с людьми. И обнаружил, что они вообще не понимают что такое медитация и зачем она нужна. Самые базовые вещи. Для них это - когда просто люди. . .
Создание Single Page Application на фреймах
krapotkin 16.11.2025
Статья исключительно для начинающих. Подходы оригинальностью не блещут. В век Веб все очень привыкли к дизайну Single-Page-Application . Быстренько разберем подход "на фреймах". Мы делаем одну. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2025, CyberForum.ru