URL: https://www.opennet.me/cgi-bin/openforum/vsluhboard.cgi
Форум: vsluhforumID9
Нить номер: 6114
[ Назад ]

Исходное сообщение
"можно ли определить занят сокет или нет?"

Отправлено L , 22-Янв-07 20:41 
На linux работает сервер, который создает разные threads для каждого клиента. И время от времени при большой загрузке получается такая ситуация:
сокет в одной из thread получает ошибку сети (например timeout или "socket closed by peer"),
  деструктор закрывает его close-ом,
    на верхнем уровне происходит откат для этой thread, который занимает некоторое время.
И если в этот самый момент появляется другая thread, то система может дать ей тот же самый дескриптор сокета, и он начинает работать.
Но
      первая thread в процессе отката вызывает "delete <дескриптор сокета>", потому что он был открыт по new <class сокет>, и получается что удаляет уже работающий сокет, да еще и не в своей области памяти, catch такое не ловит, и сервер падает.

Скажите пожалуйста, как определить, занят ли системой конкретный сокет (или адрес памяти), причем какой-то другой thread, а не текущей?


Содержание

Сообщения в этом обсуждении
"можно ли определить занят сокет или нет?"
Отправлено BigHo , 22-Янв-07 21:03 
>Скажите пожалуйста, как определить, занят ли системой конкретный сокет (или адрес памяти),
>причем какой-то другой thread, а не текущей?

привязки к конкретному потоку для файловых дескрипторов не ведется. Мне тоже этого не хватает, но по другой причине.

В данном случае как раз никакой проблемы нет. Для того, чтобы этот же номер дескриптора смог быть использован еще раз (accept ?), его обязан высвободить вызов close. Поэтому этот вызов надо задвинуть в конец деструктора. Он должен выполниться только после того, как все свзяанные структуры по этому потоку и сокету будут высвобождены (т.е. не останется ни одного указателя извне). Это конечено в идеале и тут могут быть ньюансы.

Если получится, что я чего-то недопонимаю, то кусок кода это может исправить :)


"можно ли определить занят сокет или нет?"
Отправлено L , 22-Янв-07 21:24 
>В данном случае как раз никакой проблемы нет. Для того, чтобы этот
>же номер дескриптора смог быть использован еще раз (accept ?), его
>обязан высвободить вызов close. Поэтому этот вызов надо задвинуть в конец
>деструктора. Он должен выполниться только после того, как все свзяанные структуры
>по этому потоку и сокету будут высвобождены (т.е. не останется ни
>одного указателя извне). Это конечено в идеале и тут могут быть
>ньюансы.

Да, у меня тоже пока только эта мысль, но это может оказаться очень громоздко, слишком длинная цепочка наследуемых классов


"можно ли определить занят сокет или нет?"
Отправлено BigHo , 22-Янв-07 21:41 
>Да, у меня тоже пока только эта мысль, но это может оказаться
>очень громоздко, слишком длинная цепочка наследуемых классов

Т.е. очень хочется хака ? :) Ну тогда наабум:
- убрать close из деструктора, либо заменить на dup2(_dev_null_fd, closefd), если должен быть валидным;
- создать в массиве размером getdtablesize() пометку о том, что этот дескриптор должен быть закрыт после всей череды вызова деструктора.


"можно ли определить занят сокет или нет?"
Отправлено L , 22-Янв-07 22:26 
>- убрать close из деструктора, либо заменить на dup2(_dev_null_fd, closefd), если должен быть валидным;
Точно, так и придется убирать close

>- создать в массиве размером getdtablesize() пометку о том, что этот дескриптор
>должен быть закрыт после всей череды вызова деструктора.
По сути это то же, что создавать при открытии новой thread список открытых сокетов и по завершении thread делать close для них или что-то другое?


"можно ли определить занят сокет или нет?"
Отправлено Michelnok , 22-Янв-07 22:43 
>По сути это то же, что создавать при открытии новой thread список
>открытых сокетов и по завершении thread делать close для них или
>что-то другое?

Не занимайся ерундой. Нечего делать close два раза одному и тому же дескриптору, после первого close он недействителен. На крайняк:

if(sock!=-1) {
  close(sock);
  sock=-1;
}


"можно ли определить занят сокет или нет?"
Отправлено L , 22-Янв-07 22:57 
>Не занимайся ерундой. Нечего делать close два раза одному и тому же
>дескриптору, после первого close он недействителен. На крайняк:

В том-то и дело, что во время [delete socket_descriptor] неизвестно, было уже
[close(<socket descriptor>)] или нет. А если в одной thread будет не один сокет, а несколько (например сервер по запросу клиента сам запрашивает у другого сервера и потом передает клиенту), то эти навороты с sock=-1 приведут к куче глобальных переменных, что уже само по себе плохо.


"можно ли определить занят сокет или нет?"
Отправлено Michelnok , 23-Янв-07 00:30 
>эти навороты с sock=-1 приведут к куче глобальных переменных, что уже само по себе плохо

ЗАЧЕМ ТУТ ГЛОБАЛЬНЫЕ ПЕРЕМЕННЫЕ?



"можно ли определить занят сокет или нет?"
Отправлено L , 23-Янв-07 00:54 
Затем что в данном случае (читай с самого начала) сокет оказывается принадлежащим в некоторый момент времени двум РАЗНЫМ threads


"можно ли определить занят сокет или нет?"
Отправлено Michelnok , 23-Янв-07 01:48 
>Затем что в данном случае (читай с самого начала) сокет оказывается принадлежащим
>в некоторый момент времени двум РАЗНЫМ threads

Нда...

class Socket
{
public:

  Socket()
  {
    sock=socket(...);
  }

  ~Socket()
  {
    close();
  }

  void close()
  {
    if(sock!=-1) {
      close(sock);
      sock=-1;
      }
  }

protected:
  int sock;
};

Где-то при возникновении ошибки:
  pSocket->close(); // если уж так очень хочется и не терпится должаться деструктора

Где-то позже:
  delete pSocket;

Ну, если и на этот раз непонятно, тогда я пас.


"можно ли определить занят сокет или нет?"
Отправлено Andrew , 22-Янв-07 21:14 
>На linux работает сервер, который создает разные threads для каждого клиента. И
>время от времени при большой загрузке получается такая ситуация:
>сокет в одной из thread получает ошибку сети (например timeout или "socket
>closed by peer"),
>  деструктор закрывает его close-ом,
>    на верхнем уровне происходит откат для этой thread,
>который занимает некоторое время.
>И если в этот самый момент появляется другая thread, то система может
>дать ей тот же самый дескриптор сокета, и он начинает работать.
>
>Но
>      первая thread в процессе отката вызывает "delete <дескриптор сокета>", потому что он был открыт по new <class сокет>, и получается что удаляет уже работающий сокет, да еще и не в своей области памяти, catch такое не ловит, и сервер падает.
>
>Скажите пожалуйста, как определить, занят ли системой конкретный сокет (или адрес памяти),
>причем какой-то другой thread, а не текущей?

перечитывай свой вопрос пока не поймешь в чем его глупость.
подсказка: если так и не поймешь - спрашивай.