Форум программистов «Весельчак У»
  *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

  • Рекомендуем проверить настройки временной зоны в вашем профиле (страница "Внешний вид форума", пункт "Часовой пояс:").
  • У нас больше нет рассылок. Если вам приходят письма от наших бывших рассылок mail.ru и subscribe.ru, то знайте, что это не мы рассылаем.
   Начало  
Наши сайты
Помощь Поиск Календарь Почта Войти Регистрация  
 
Страниц: [1]   Вниз
  Печать  
Автор Тема: завершение потока выполняющего accept()  (Прочитано 20750 раз)
0 Пользователей и 2 Гостей смотрят эту тему.
goodness
Гость
« : 05-09-2006 13:03 » new

Когда пишут приложение использующие сокеты зачастую создают поток, который обрабатывает подключение новых клиентов к серверу. Для стандартной BSD функции выгледит это примерно так:

Код:
TempSock = accept( ListeningSock, (struct sockaddr *) &Sin, &Sin_len);

Соответсвенно поток на этой функции "повисает" и возвращает управление только когда появиться какое-нибудь соединение.

Собственно вопрос в том, как правильно завершить подобный поток. Скажем, если мы хотим завершить поток поключений из другого потока, то в другом потоке зачастую пишут так:

Код:
ListeningSock = INVALID_SOCKET

после ждут когда поток завершиться, т.к. accept() вернет управдение.


И не смотря на то, что это, в принципе, работает, почему-то кажется, что делать так опасно ибо мы пишем в ListeningSock в одном потоке и одновременно можем обращаться к ней в другом потоке.

Ситуация достаточная распространенная. Мне интересно как ее обычно решают. Как правильно завершить слушающий поток? И правомерно ли его завершать так как я описал?
Записан
Finch
Спокойный
Администратор

il
Offline Offline
Пол: Мужской
Пролетал мимо


« Ответ #1 : 05-09-2006 13:16 » 

goodness, Можно сокет перевести в неблокируюший режим (статья https://club.shelek.ru/viewart.php?id=153). Код программы чуть усложнится, но зато отпадет надобность в принудительном убиении потоков.

Кстати может быть топик лучше перенести в раздел программирование С++/Unix или в раздел Сеть?
« Последнее редактирование: 05-09-2006 13:26 от Finch » Записан

Не будите спашяго дракона.
             Джаффар (Коша)
Finch
Спокойный
Администратор

il
Offline Offline
Пол: Мужской
Пролетал мимо


« Ответ #2 : 05-09-2006 13:30 » 

В Linux комманда перевода сокета в неблокируюший режим
Код:
        param=1;
    ioctl(sdin,  FIONBIO, &param);
Записан

Не будите спашяго дракона.
             Джаффар (Коша)
npak
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #3 : 05-09-2006 13:58 » 

Надо пользоваться связкой select/accept
Функция select ожидает появления события в нескольких сокетах, причём можно задать ограничение на время ожидания. 

Документация для Майкрософт
http://msdn.microsoft.com/library/en-us/winsock/winsock/select_2.asp

Пример.
http://www.lowtek.com/sockets/select.html
Записан

UniTesK -- индустриальная технология надежного тестирования.

http://www.unitesk.com/ru/
nikedeforest
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #4 : 05-09-2006 14:07 » 

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

ещё один вопрос ...
Finch
Спокойный
Администратор

il
Offline Offline
Пол: Мужской
Пролетал мимо


« Ответ #5 : 05-09-2006 14:17 » 

nikedeforest цитирую статью, ссылку на которую я дал ранее:
Цитата
После переключения сокета в неблокирующий режим, вызовы Winsock API связанные с приемом, передачей данных либо управлением соединений будут сразу возвращять управление прилоежению, не ожидая завершения текущей операции. В большинстве случаев данные вызовы возвращают ошибку типа WSAEWOULDBLOCK, что означает, что операция не имела времени закончится в период вызова функции. К примеру функция recv вернет WSAEWOULDBLOCK если нет ожидающих данных в системном буфере для данного сокета. Часто нужны дополнительные вызовы функции пока она не вернет сообшение об удачном завершение операции. Следующая таблица описывает значение WSAEWOULDBLOCK при вызове разных Winsock API функций:
Т.е нужно все время при выходе из функции запрашивать код ошибки. Если он равен WSAEWOULDBLOCK то просто делать запрос в функцию повторно. Я в таком случае еше делал проверку нету ли сообшения обшего выхода из программы.
Записан

Не будите спашяго дракона.
             Джаффар (Коша)
npak
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #6 : 05-09-2006 14:40 » 

Finch,

при таком подходе функция будет постоянно тратить CPU на цикл
Код:
#define ON_ERROR 1
#define ON_EXIT 2
int break_reason_reason = 0;

while (1) {
    if (accept(...) < 0) {
        if (errno != EAGAIN && errno != EWOULDBLOCK) {
            // выход из цикла по ошибке
            break_reason = ON_ERROR;
            break;
        }
        if (/* проверка условия завершения потока */) {
            break_reason = ON_EXIT;
            break;
        }
        // Сон в течение некоторого времени.
        continue;
  } else {
    // Обработка нового соединения
  }
}

Использование select предпочтительней.
Записан

UniTesK -- индустриальная технология надежного тестирования.

http://www.unitesk.com/ru/
Finch
Спокойный
Администратор

il
Offline Offline
Пол: Мужской
Пролетал мимо


« Ответ #7 : 05-09-2006 15:07 » 

npak, Согласен. Но у goodness вопрос по BSD. Я сейчас просмотрел книжку по сокетам Линуксу и просмотрел заголовочные файлы и такой функции не нашел.
Записан

Не будите спашяго дракона.
             Джаффар (Коша)
npak
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #8 : 05-09-2006 15:20 » 

Ищи лучше Улыбаюсь select - базовая функция интерфейса сокетов.  В BSD присутствует с момента создания API сокетов.

man select
Записан

UniTesK -- индустриальная технология надежного тестирования.

http://www.unitesk.com/ru/
Finch
Спокойный
Администратор

il
Offline Offline
Пол: Мужской
Пролетал мимо


« Ответ #9 : 05-09-2006 15:42 » 

Она описывается в не сокетах Улыбаюсь, Поэтому сразу и не нашел. Вот описание под Линукс http://www.gnu.org/software/libc/manual/html_node/Waiting-for-I_002fO.html#Waiting-for-I_002fO
Пока искал описание, нашел пример сервера
http://www.gnu.org/software/libc/manual/html_node/Server-Example.html#Server-Example

Записан

Не будите спашяго дракона.
             Джаффар (Коша)
RXL
Технический
Администратор

ru
Offline Offline
Пол: Мужской

WWW
« Ответ #10 : 05-09-2006 15:59 » 

goodness, Finch, nikedeforest, не надо смешивать в одну кучу разные вещи.

Во-первых, ListeningSock = INVALID_SOCKET не даст никакого результата, если accept() уже работает.
Во-вторых, не надо путать неблокируемость и ассинхронность - это разные вещи. Операция над неблокируемым сокетом отработает точно так же, как и над блокируемым, если есть все условия для выполнения, а иначе операция вернет ошибку о неготовности. Ассинхронные операции - фоновые по отношению к инициирующему их потоку. Под такие операции создаются отдельные потоки, которые и блокируются на время операции. Поток может быть создан run-time библиотекой автоматически.

Для использования с select() неблокируемость не имеет значения.

Прервать блокируемую операцию в *nix легко - послать незамаскированный сигнал. Что в этом случае нужно сделать в винде - не знаю.
Записан

... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
nikedeforest
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #11 : 06-09-2006 10:25 » 

Вот какие выводы я сделал на данный момент. С помощью функции select я перевошу синхронные функции в неблокирующий режим. Ассинхронными же функциями являются функции WSA... (WSAAccept к примеру ).
Следующее -  небллокирующие функции и ассинхронные функции - это не одно и тоже. Но теперь хотелось бы наверняка осмыслить насколько это не одно и тоже.

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

Неблокирующие операции.Это не отдельный поток. А что же тогда эта операция из себя представляет? Я понял, что она сразу же возвращает ошибку, давая тем самым зеленый свет работе потока, запустившего неблокирующую операцию. Но ... как же она в этом случае выполняется? И она же все равно по идеи должна в каком-то отдельном потоке выполняться? Как иначе? Вот никак не могу понять.
з.ы. синхронные функции ==синхронные сокеты.
« Последнее редактирование: 06-09-2006 10:29 от nikedeforest » Записан

ещё один вопрос ...
RXL
Технический
Администратор

ru
Offline Offline
Пол: Мужской

WWW
« Ответ #12 : 06-09-2006 17:58 » 

Цитата
небллокирующие функции
Нет таких ф-ий! Есть неблокирующиеся сокеты (правильнее - дескрипторы файлов, но в винде это разные вещи).

Цитата
С помощью функции select я перевошу синхронные функции в неблокирующий режим.
Неверно! select() ожидает готовность любого из дескрипторов в списке. Принимает три списка для проверок готовности на: чтение, запись, ошибку. Вызов select() блокирует поток до появления любого из заданных параметрами событий.

Блокируемость определяется лишь признаком в структуре, описывающей файл.
Все операции одинаковы, но если их невозможно выполнить сразу, то проверяется признак блокируемости. Если дескриптор неблокируемый, то происходит возврат в вызывавшую программу, а иначе поток ставится на ожидание.
Фича с неблокируемостью - наследие прошлого и применения ей я не нахожу.

Соотв., после возврата из select() дескриптор готовый, к примеру, к чтению не вызовет блокировки на операции чтения вне зависимости от признака блокируемости.

Насчет ассинхронных операций - обратись к документации ОС, под которую пишешь. В данном случае - MSDN.


Ну и бред же ты выдаешь, Шарапов Улыбаюсь Не надо напрягать фантазию, а лучше почитать литературу. Принципы довольно простые.
Записан

... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
sss
Специалист

ru
Offline Offline

« Ответ #13 : 07-09-2006 02:34 » 

А если в другом потоке выдать (win)...

Код:

  fHaltingInProgress = 1;
  closesocket( ListeningSock);

  //Ждем окончания потока
  WaitForSingleObject ( hAcceptor, MAX_WAIT);

то accept вываливается из ожидания с TempSock == INVALID_SOCKET (WSAGetLastError() == WSAEINTR). Можно еще при этом использовать какой либо флажок (например fHaltingInProgress).

Записан

while (8==8)
RXL
Технический
Администратор

ru
Offline Offline
Пол: Мужской

WWW
« Ответ #14 : 07-09-2006 14:11 » 

sss, логично Улыбаюсь Что-то я про этот метод забыл...
Записан

... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
Страниц: [1]   Вверх
  Печать  
 

Powered by SMF 1.1.21 | SMF © 2015, Simple Machines