The OpenNET Project / Index page

[ новости /+++ | форум | теги | ]

форумы  помощь  поиск  регистрация  майллист  вход/выход  слежка  RSS
"Сокеты и сбои. Кто неправ?"
Вариант для распечатки  
Пред. тема | След. тема 
Форумы Программирование под UNIX (Public)
Изначальное сообщение [ Отслеживать ]

"Сокеты и сбои. Кто неправ?"  +/
Сообщение от crazy_blu (ok) on 18-Июл-09, 00:22 
Здравствуйте.
Я понимаю что вопрос будет звучать глупо, но все-же...
Пишется многопоточное приложение. Потоки ходят по серверам и проверяют их работоспособность. Все работает замечательно до...
Подсовываем одному из потоков невалидное имя. gethostbyname() возвращает NULL и дальше... остальные соединения начинают работать вразлад - когда коннектятся, когда нет... Причем имена разрезолвливаются, отказы идут на вызове connect().
Все вызовы стандартные блокирующие, вроде почти академическая задача... Почему возникают такие проблемы непонятно.
Не нужно ли как-то дполнительно сбрасывать/переинициаизировать ядро после неудачного резолва имени?

С уважением,
Сергей

Высказать мнение | Ответить | Правка | Cообщить модератору

 Оглавление

Сообщения по теме [Сортировка по времени | RSS]


1. "Сокеты и сбои. Кто неправ?"  +/
Сообщение от jd (??) on 18-Июл-09, 00:40 
>Не нужно ли как-то дполнительно сбрасывать/переинициаизировать ядро после неудачного резолва имени?

Очевидно нет. И при чём тут вообще ядро? Вероятно причина кроется где-то вне описанных вами исходных данных.

Высказать мнение | Ответить | Правка | Наверх | Cообщить модератору

2. "Сокеты и сбои. Кто неправ?"  +/
Сообщение от crazy_blu (ok) on 18-Июл-09, 11:16 
>>Не нужно ли как-то дполнительно сбрасывать/переинициаизировать ядро после неудачного резолва имени?
>
>Очевидно нет. И при чём тут вообще ядро? Вероятно причина кроется где-то
>вне описанных вами исходных данных.

Я же сказал что вопрос выглядит глупым. Но больше идей нет.
Пример сейчас. 4 потока. Каждый лезет на свой адрес. www.yandex.ru www.google.com www.google.com и www.microsoft.com
По каждому потоку - открывает сокет, резолвит имя, открывает соединениек на порт 80, посылает HTTP-запрос, читает HTTP-ответ, закрывает сокет.

Пока все имена валидные - все хорошо. Как только меняю (динамически) имя для второго потока на www.xgoogle.com ( канселим тред, запускаем новый ) -наступает разнобой.

Тогда вопрос так поставим. По умолчанию ВРОДЕ при pthread_cancel() тред останавливается и все его handle освобождаются. Подразумевается что закрывается сокет?
А как обработка идет если тред в это время заблокирован gethostbyname() или connect()? Сделать параллельно shutdown() на этот же сокет? А можно разве так?

Сергей.
PS. А если обрабатывать - какой сигнал? SIG... ??

Высказать мнение | Ответить | Правка | Наверх | Cообщить модератору

5. "Сокеты и сбои. Кто неправ?"  +/
Сообщение от svn (??) on 18-Июл-09, 13:14 
>Тогда вопрос так поставим. По умолчанию ВРОДЕ при pthread_cancel() тред останавливается и
>все его handle освобождаются. Подразумевается что закрывается сокет?

Нет. У thread нет  сокетов, только у процесса.

>А как обработка идет если тред в это время заблокирован gethostbyname() или
>connect()?

В зависимости от реализации. ЧИтай мануалы.

обычно  pthread_cancel останавливает только когда поток в хорошем состоянии (cancellation point)

Высказать мнение | Ответить | Правка | Наверх | Cообщить модератору

3. "Сокеты и сбои. Кто неправ?"  +/
Сообщение от svn (??) on 18-Июл-09, 11:44 
>Подсовываем одному из потоков невалидное имя. gethostbyname() возвращает NULL и дальше... остальные
>отказы идут на вызове connect().

Какие такие отказы? ))

Высказать мнение | Ответить | Правка | Наверх | Cообщить модератору

4. "Сокеты и сбои. Кто неправ?"  +/
Сообщение от crazy_blu (ok) on 18-Июл-09, 13:09 
>>Подсовываем одному из потоков невалидное имя. gethostbyname() возвращает NULL и дальше... остальные
>>отказы идут на вызове connect().
>
>Какие такие отказы? ))

Я не разбирался в кодах ошибок. Просто сам факт - до этого все вызовы connect() возвращали значение =0 (успешное завершение), теперь стали <0 (как говорится если хотите - смотрите код ошибки).
Интересен не код - почему послали. Интересен и непонятен сам факт - почему на факт неудачного резолва имени перестает корректно работать сам стек. Или (см мой ответ выше) некорректно что-то канселится????

Высказать мнение | Ответить | Правка | Наверх | Cообщить модератору

6. "Сокеты и сбои. Кто неправ?"  +/
Сообщение от svn (??) on 18-Июл-09, 13:19 
>Я не разбирался в кодах ошибок.

А вот и разберись, будет понятнее.

>Интересен не код - почему послали.

этот код и есть причина!! Детский сад штаны на лямках.

>почему на факт неудачного резолва имени перестает корректно работать сам стек.

1. Обрабатывай ошибки всез системных вызовов.
2. Запусти программу в valgrind
3. Запусти программу в отладчике, проверь как работают функции.

>Или (см мой ответ выше) некорректно что-то канселится????

Прерывать потоки глупо практически всегда.

Высказать мнение | Ответить | Правка | Наверх | Cообщить модератору

7. "Сокеты и сбои. Кто неправ?"  +/
Сообщение от crazy_blu (ok) on 18-Июл-09, 16:06 
>>Интересен не код - почему послали.
>этот код и есть причина!! Детский сад штаны на лямках.

Ну хорошо - код ошибки как правило CONNECTION REFUSED
Почему? Кто? За что?

>>Или (см мой ответ выше) некорректно что-то канселится????
>Прерывать потоки глупо практически всегда.

А как их корректно завершать? Проверять постоянно какой-то флаг? Но это неправильно.
Обрабатывать сигналы? Но обработка сигнала идет в контексте потока? Если из обработчика сигнала я скажу pthread_exit() - это будет корректно?

Сергей

PS. Спасибо за ответы, помогает местами.

Высказать мнение | Ответить | Правка | Наверх | Cообщить модератору

8. "Сокеты и сбои. Кто неправ?"  +/
Сообщение от svn (??) on 18-Июл-09, 16:53 
>Ну хорошо - код ошибки как правило CONNECTION REFUSED
>Почему? Кто? За что?

На другом конце тебя не ждут. Наверно адрес не правильный )) Наверно ты адрес из имени не правильно получаешь. Как ты это делаешь?

>А как их корректно завершать?

Правильно вообще не завершать. Поток отработал и завершился сам, или встал в очередь за новым заданием. Разумеется не должен зависать ))

>Проверять постоянно какой-то флаг? Но это неправильно.

Это правильнее чем внешнее прерывание потока, которое потенциальная утечка ресурсов и не  может использоваться для управления работой, максимум обработка ошибок.

>Обрабатывать сигналы?

Сигналы как и сокеты - принадлежат процессу. Посылать сигналы потокам было возможно используя недокументированные возможности некоторых реализаций. Надеятся на такую возможность глупо.

Высказать мнение | Ответить | Правка | Наверх | Cообщить модератору

10. "Сокеты и сбои. Кто неправ?"  +/
Сообщение от crazy_blu (ok) on 18-Июл-09, 22:17 
>>Ну хорошо - код ошибки как правило CONNECTION REFUSED
>>Почему? Кто? За что?
>На другом конце тебя не ждут. Наверно адрес не правильный )) Наверно
>ты адрес из имени не правильно получаешь. Как ты это делаешь?

  struct hostent    * hp;
  struct sockaddr_in  sAddr;
  ...
  if( NULL == (hp = gethostbyname( strBuff )) )
  {
    error( ... );
    goto finish;
  }
  memset( &sAddr, 0, sizeof( sAddr ) );
  memcpy( &sAddr.sin_addr, hp->h_addr, hp->h_length );
  sAddr.sin_family = hp->h_addrtype;
  sAddr.sin_port   = htons(req->n_PortNumber);
  if( 0 > connect( req->socket, (struct sockaddr*) &sAddr, sizeof(sAddr) ) )
  {
    error( ... );
    goto finish;
  }
  ...

>>А как их корректно завершать?
>Правильно вообще не завершать. Поток отработал и завершился сам, или встал в
>очередь за новым заданием. Разумеется не должен зависать ))
>>Проверять постоянно какой-то флаг? Но это неправильно.
>Это правильнее чем внешнее прерывание потока, которое потенциальная утечка ресурсов и не
> может использоваться для управления работой, максимум обработка ошибок.

Вот пример. Процесс обработки довольно длительный и состоит из нескольких этапов. Хочется его прервать (прекратить) в любой момент. Аппаратно для этого есть прерывания. Из которого управление можно и вернуть процессу(треду), а можно кому другому отдать. А как управлять одним тредом из другого? Прекращать по желанию, корректно освобождая ресурсы завершаемого треда? Ставить по всему телу процесса проверку флага?
Фактически это то-же аппарат исключения, событийного исключения, только событие происходит не из самого процесса, а снаружи.

Сергей.

Высказать мнение | Ответить | Правка | Наверх | Cообщить модератору

11. "Сокеты и сбои. Кто неправ?"  +/
Сообщение от svn (??) on 19-Июл-09, 00:22 
>  if( NULL == (hp = gethostbyname( strBuff )) )

Не надо пользоваться gethostbyname в многопоточной программе. Она использует статический буфер для результата.  И если её вызвать из двух потоков одновременно данные будут испорчены. Ты соединялся не с теми. но пока резолвилось нормально ты не замечал ошибку и не знал об этом ))

Используй gethostbyname_r, а лучше getaddrinfo. В однопоточной программе тоже.

>Вот пример. Процесс обработки довольно длительный и состоит из нескольких этапов.
>Хочется >его прервать (прекратить) в любой момент.

А как будешь освобождать ресурсы? А сохранять промежуточные результаты? А возвращать в корректное состояние?
Прервал - и всё чудом вернулось как и было, или даже нет, все правильные изменения остались, а всё недоделанное откатилось )) Это чудо похлеще деда мороза.

Хочется - это не аргумент.
Альтернатива потоку проверять не пора ли освободить ресурсы и завершать работу - это писать в некий журнал все ресурсы, и потом тот кто завершает работу потока их освобождает. Но опять же, тебе интересно блокировка потока вызывающего завершение другого потока до тех пор пока он не завершится?
Удобных мест для проверки в долгих задачах полно, не понимаю в чём проблема ))
А в коротких - прерывать нет смысла, быстрее задача завершится.

PS: А вообще для твоей задачи потоки не нужны ))

Высказать мнение | Ответить | Правка | Наверх | Cообщить модератору

12. "Сокеты и сбои. Кто неправ?"  +/
Сообщение от crazy_blu (ok) on 19-Июл-09, 21:56 
>Не надо пользоваться gethostbyname в многопоточной программе. Она использует статический буфер для
>результата.  И если её вызвать из двух потоков одновременно данные
>будут испорчены. Ты соединялся не с теми. но пока резолвилось нормально
>ты не замечал ошибку и не знал об этом ))
>
>Используй gethostbyname_r, а лучше getaddrinfo. В однопоточной программе тоже.

Спасибо, ошибку понял!

>>Вот пример. Процесс обработки довольно длительный и состоит из нескольких этапов.
>>Хочется >его прервать (прекратить) в любой момент.
>А как будешь освобождать ресурсы? А сохранять промежуточные результаты? А возвращать в
>корректное состояние?
>Прервал - и всё чудом вернулось как и было, или даже нет,
>все правильные изменения остались, а всё недоделанное откатилось )) Это чудо
>похлеще деда мороза.

В SQL-серверах это называется транзакции. Они или комитятся или rollback :) Хочется аналогичное и по тредам :)

>Хочется - это не аргумент.

Ну согласен, но с другой строны, если бы не было желания, никто ничего бы и не делал :)

>PS: А вообще для твоей задачи потоки не нужны ))

Заказчик хочет так. Кстати я не знаю что лучше для многих (неск. тысяч) запросов по разным адресам - много тредов или большие списки в select?

Высказать мнение | Ответить | Правка | Наверх | Cообщить модератору

16. "Сокеты и сбои. Кто неправ?"  +/
Сообщение от Kindzadza on 06-Авг-09, 19:24 
>
>Заказчик хочет так. Кстати я не знаю что лучше для многих (неск.
>тысяч) запросов по разным адресам - много тредов или большие списки
>в select?

Несколько threads и select. Создавать пару тысячь тредов - идиотизм.

Высказать мнение | Ответить | Правка | Наверх | Cообщить модератору

9. "Сокеты и сбои. Кто неправ?"  +/
Сообщение от Аноним (??) on 18-Июл-09, 20:52 
>[оверквотинг удален]
>работает замечательно до...
>Подсовываем одному из потоков невалидное имя. gethostbyname() возвращает NULL и дальше... остальные
>соединения начинают работать вразлад - когда коннектятся, когда нет... Причем имена
>разрезолвливаются, отказы идут на вызове connect().
>Все вызовы стандартные блокирующие, вроде почти академическая задача... Почему возникают такие проблемы
>непонятно.
>Не нужно ли как-то дполнительно сбрасывать/переинициаизировать ядро после неудачного резолва имени?
>
>С уважением,
>Сергей

Может Вам стоит попробовать вместо gethostbyname() использовать gethostbyname_r().


Высказать мнение | Ответить | Правка | Наверх | Cообщить модератору

13. "Сокеты и сбои. Кто неправ?"  +/
Сообщение от blackswan (ok) on 06-Авг-09, 10:18 
А у меня другая проблема. Использую чужой код, который по идее должен работать как сокет-сервер. В hostname - char имя хоста или IP, в port - номер порта.
  sockaddr_in service;
  memset(&service, 0, sizeof(sockaddr_in));
  service.sin_family = AF_INET;
  service.sin_addr.s_addr = inet_addr(hostname);

  if (service.sin_addr.s_addr == INADDR_NONE)
  {
    struct hostent *host = gethostbyname(hostname);
    if (host == NULL || host->h_addr == NULL)
    {
      printf( "Problem accessing the DNS. (addr: %s)", hostname);
      return false;
    }
    service.sin_addr = *(struct in_addr*)host->h_addr;
  }
  service.sin_port = htons(port);
  m_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
  if (m_socket != -1)
  {
    if (connect(m_socket, (sockaddr*) &service, sizeof(struct sockaddr)) < 0)
    {
      printf( "%s, failed to connect socket. Error: %d\n", " ", GetSockError());
      perror("connect");
    }
  }
m_socket получает значение, однако при вызове connect получаю сообщение 61 Connection refused.

Высказать мнение | Ответить | Правка | Наверх | Cообщить модератору

14. "Сокеты и сбои. Кто неправ?"  +/
Сообщение от crazy_blu (ok) on 06-Авг-09, 10:45 
>А у меня другая проблема. Использую чужой код, который по идее должен
>работать как сокет-сервер. В hostname - char имя хоста или IP,
>в port - номер порта.
>    struct hostent *host = gethostbyname(hostname);

[skip]

>    if (connect(m_socket, (sockaddr*) &service, sizeof(struct sockaddr)) < 0)

[skip]

>m_socket получает значение, однако при вызове connect получаю сообщение 61 Connection refused.
>

У меня проблема решилась использованием gethostbyname_r() т.к. gethostbyname() работает со статическим внутренним буфером и требы могут портить его друг у друга.

А вообще не вредно посмотреть промежуточно что и как отдается как адрес для соединения.

Высказать мнение | Ответить | Правка | Наверх | Cообщить модератору

15. "Сокеты и сбои. Кто неправ?"  +/
Сообщение от blackswan (ok) on 06-Авг-09, 11:05 
>
>У меня проблема решилась использованием gethostbyname_r() т.к. gethostbyname() работает со статическим внутренним
>буфером и требы могут портить его друг у друга.
>
>А вообще не вредно посмотреть промежуточно что и как отдается как адрес
>для соединения.

Если я испльзую не имя, а адрес и тогда gethostbyname не срабатывает, то та же ошибка с connect, адрес у меня "127.0.0.1", превращается в значение 16777343 для service.sin_addr.s_addr.


Высказать мнение | Ответить | Правка | Наверх | Cообщить модератору

Архив | Удалить

Индекс форумов | Темы | Пред. тема | След. тема




Партнёры:
PostgresPro
Inferno Solutions
Hosting by Hoster.ru
Хостинг:

Закладки на сайте
Проследить за страницей
Created 1996-2024 by Maxim Chirkov
Добавить, Поддержать, Вебмастеру