LINUX.ORG.RU

Бред с сокетами и select.


0

0

Может кто сталкивался с подобной проблеммой:

Открываю несколько сокетов, получаю их дескрипторы потом передаю
их select, чтобы тот ждал когда в них можно будет писать/читать.

select мне возвращает, что скажем 4 дескриптор доступен и для
чтения и для записи, при попытке прочитать данные, read крепко
задумывается, типа данных нет. Пробовал повторно передавать
этот же дескриптора select-у, он уже не выдает его как
доступный для чтения.
Схематично ситуация выглядит следующим образаом

1) Открываем сокеты -> [3,4,5,6]
2) Первый вызов select
select [3,4,5,6] [3,4,5] [] -> [4] [4] []
3) Второй вызов select
select [4] [4] [] -> [] [4] []

Что за чепуха такая, в чем может быть дело?


Что за сокеты (в смысле, для listen или для connect, или UDP)? В
каком они состоянии на момент select? Нету ли ненароком OOB data?
Для очиски совести попробуйте recv со всеми флагами.

vnp
()

и кроме вышесказанного: сокеты-то хоть в неблокирующем режиме?

svd
()

> Может кто сталкивался с подобной проблеммой:...
Я сталкивался, месяца 3 назад - точно те же симптомы, даже сюда хотел писАть.
Потом оказалось, что я просто перепутал сокеты (R с W) :-)

Поищи ошибку в алгоритме. 99%, найдешь.

svd (*) (2002-11-01 00:46:46.79):
> и кроме вышесказанного: сокеты-то хоть в неблокирующем режиме?
Очепятка?
Из постинга понятно, что они в БЛОКИРУЮЩЕМ режиме. А если бы были в НЕ блокирующем,
то селект как бы и не при чем...

Die-Hard ★★★★★
()

Система следующая
1) Перевожу сокет в неблокирующий режим
2) Делаю connect, он мне говорит что мол я в процессе( EINPROGRESS)
3) Передаю дескриптор сокета select, чтобы он его проверял и на чтение и на запись( oob data нет)
4) select в результате говорит что сокет мол доступен и для чтения и для записи
5) перевожу сокет в блокирующий режим, пытаюсь из него читать, и в этом месте вылазит жопа, read задумывается, а потом возвращает 0, вроде как EOF.

Причем такая ситуация вылазит с вероятностью 1/3, в остальных случаях п.4 говорит что сокет доступен только для записи.

Еще одно наблюдение, такая херня творится только на 2-х процессорной системе, под ядром 2.2.21, на одно-процессорной машине с 2.2.14 п.4 возвращает исследуемый дескриптор только как доступный для записи.

temofey
() автор топика
Ответ на: комментарий от temofey

temofey (*) (2002-11-01 10:49:21.35):
Дык, у тебя коннект не встал. Прямо по ФАКу.

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

Надо дождаться, пока select() выдаст writability. Затем с помощью
getsockopt(2) прочитать SO_ERROR на левеле SOL_SOCKET. Если 0, то встало,
иначе - нет.


Если селект выдал readability на неблокирующий сокет после connect -1/EINPROGRESS,
то это ничего не значит! Например,
http://www.manualy.sk/sock-faq/unix-socket-faq-6.html

Die-Hard ★★★★★
()

Die-Hard (*) (2002-11-01 01:45:52.513)
> Очепятка?
> Из постинга понятно, что они в БЛОКИРУЮЩЕМ режиме. А если бы были в НЕ блокирующем,
> то селект как бы и не при чем...
А какой смысл использовать блокирующий сокет и select()?

temofey (*) (2002-11-01 10:49:21.35)
> 5) перевожу сокет в блокирующий режим, пытаюсь из него читать, и в этом месте вылазит жопа, read задумывается, а потом возвращает 0, вроде как EOF.
А почему бы не задуматься на read(), если сокет блокирующий?
Если уж использовать select(), то не надо переводить сокет в блокирующий режим

svd
()

Die-Hard (*) (2002-11-01 18:39:28.088)
> Дык, у тебя коннект не встал. Прямо по ФАКу.
А линк можно?

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

> Надо дождаться, пока select() выдаст writability. Затем с помощью
> getsockopt(2) прочитать SO_ERROR на левеле SOL_SOCKET. Если 0, то > встало,иначе - нет.
В том и дело что первый вызов select говорит - сокет готов
и для _ЗАПИСИ_ и для _ЧТЕНИЯ_, и SO_ERROR тоже ноль, а на
самом деле для чтение сокет не готов.


> Если селект выдал readability на неблокирующий сокет
> после connect -1/EINPROGRESS,
> то это ничего не значит!
Да вроде значит. Насколько я правильно понял ситуация здесь с точностью наоборот, select на открытом сокете может вернуть что он не доступен для чтения в связи с тем что в сокете нет данных, тогда как на запись он становиться доступным сразу после открытия.


svd (*) (2002-11-02 00:25:16.147)
> А почему бы не задуматься на read(), если сокет блокирующий?
> Если уж использовать select(), то не надо переводить сокет в
> блокирующий режим

$ man select
....
Those listed in readfds will be watched to see if characters become available for reading,
....

Т.е. если select вернул дескриптор как доступный для чтения,
то read задумываться не должен, потому что в нем( дескрипторе) уже есть "characters become available for reading".

temofey
() автор топика

> Т.е. если select вернул дескриптор как доступный для чтения,
> то read задумываться не должен, потому что в нем( дескрипторе) уже есть "characters become available for reading".

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

anonymous
()
Ответ на: комментарий от anonymous

anonymous (*) (2002-11-03 02:57:01.941):
> read не будет задумываться только в том случае, если сокет в неблокирующем режиме.
> А если сокет в блокирующем режиме, и доступно для чтения больше байт, чем запрошено,
> то read будет заблокирован.

Нет. Почитай man 2 read; попробуй сам!

Die-Hard ★★★★★
()
Ответ на: комментарий от svd


svd (*) (2002-11-02 00:25:16.147):
> А какой смысл использовать блокирующий сокет и select()?
Типа, select() именно для этого и задумывался. Использование select()а
с не блокирующим дескриптором - экзотика, типа обсуждаемого connect()'a

> А почему бы не задуматься на read(), если сокет блокирующий?
RTFM (man 2 select)

Die-Hard ★★★★★
()
Ответ на: комментарий от temofey

>Die-Hard (*) (2002-11-01 18:39:28.088)
>> Дык, у тебя коннект не встал. Прямо по ФАКу.
>А линк можно?
Я привел один линк на ФАКи. Еще раз:
http://www.manualy.sk/sock-faq/unix-socket-faq-6.html

> В том и дело что первый вызов select говорит - сокет готов
> и для _ЗАПИСИ_ и для _ЧТЕНИЯ_, и SO_ERROR тоже ноль, а на
> самом деле для чтение сокет не готов.
Глюк! Так не бывает :)

> select на открытом сокете может вернуть что он не доступен для чтения в связи
> с тем что в сокете нет данных, тогда как на запись он становиться доступным
> сразу после открытия.
man 2 connect:
...
EINPROGRESS
The socket is non-blocking and the connection can╜
not be completed immediately. It is possible to
select(2) or poll(2) for completion by selecting
the socket for writing. After select indicates
writability, use getsockopt(2) to read the SO_ERROR
option at level SOL_SOCKET to determine whether
connect completed successfully (SO_ERROR is zero)
or unsuccessfully (SO_ERROR is one of the usual
error codes listed here, explaining the reason for
the failure).

> Т.е. если select вернул дескриптор как доступный для чтения,
> то read задумываться не должен,...
Насколько я знаю, это однозначно верно для БЛОКИРУЮЩЕГО дескриптора.
Спробуй перед read'ом, когда дескроптор уже блокирует, еще разок его проselectить,
хуже не будет.

Кстати, во избежании подобных проблем рекомендую делать коннект на БЛОКИРУЮЩЕМ
сокете в дочернем процессе/треде, а папа пусть таймаут делает, см
"Проблема с таймаутом :(((" несколькими тредами ниже,
http://www.linux.org.ru/view-message.jsp?msgid=242231

Die-Hard ★★★★★
()

> Глюк! Так не бывает :)
Еще как бывает. strace output привести?

> Кстати, во избежании подобных проблем рекомендую
> делать коннект на БЛОКИРУЮЩЕМ
> сокете в дочернем процессе/треде,

Я вообщемто с select и связался для того чтобы забыть
о fork и threads, поэтому метод не катит.


В общем я понял что описанная ситуация есть на что иное как
некоторая особенность, некоторых ядер на некоторых аппаратных
архитектурах, зная эту особенность нетрудно ее обойти.
Теперь я первому select-у вместо
select [4] [4] [], передаю select [] [4] [], т.е. проверяю сокет
исключительно только на запись.




temofey
() автор топика
Ответ на: комментарий от temofey

temofey (*) (2002-11-04 11:23:31.825):
>> Глюк! Так не бывает :)
>Еще как бывает. strace output привести?
Дык - верю. Просто, глюк-с!

> Я вообщемто с select и связался для того чтобы забыть
> о fork и threads, поэтому метод не катит.
Ну, хозяин - барин.
Замечу только, что fork() значительно портабильнее getsockopt().

> Теперь я первому select-у вместо select [4] [4] [], передаю select [] [4] [],
> т.е. проверяю сокет исключительно только на запись.
Кстати, в man connect() в пункте про EINPROGRESS именно так и написано ;)


Die-Hard ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.