LINUX.ORG.RU

Зависание в boost asio на операции чтения из сокета

 , ,


0

4

Клиент делает приблизительно следующее:

tcp::resolver resolver( io_service );
tcp::resolver::query query( tcp::v4(), "localhost", "5556" );
socket_.connect( *resolver.resolve( query ), ec );

socket_.send( boost::asio::buffer( ss2.str() ) );
socket_.receive( boost::asio::buffer( buffer_ ) );
Сервер асинхронно принимает соединения от клиента, асинхронно читает из сокета socket_.async_read_some(...), затем записывает ответ асинхронно boost::asio::async_write( socket_, ... ).
Так вот, периодически (очень редко) происходит зависание в socket_.receive() на клиенте. ЧЯДНТ?
Количество соединений на локалхосте где-то порядка пары сотен в секунду.



Последнее исправление: nerdogeek (всего исправлений: 1)

Так вот, периодически (очень редко) происходит зависание в socket_.receive() на клиенте. ЧЯДНТ?

Кэп подсказывает, что сервер нифига не посылает.

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

Посылает. Но netstat -t показывает дофигищу сокетов в TIME_WAIT.
ulimit -a показывает:

core file size          (blocks, -c) 0
data seg size           (kbytes, -d) unlimited
scheduling priority             (-e) 0
file size               (blocks, -f) unlimited
pending signals                 (-i) 13971
max locked memory       (kbytes, -l) 64
max memory size         (kbytes, -m) unlimited
open files                      (-n) 1024
pipe size            (512 bytes, -p) 8
POSIX message queues     (bytes, -q) 819200
real-time priority              (-r) 0
stack size              (kbytes, -s) 8192
cpu time               (seconds, -t) unlimited
max user processes              (-u) 1024
virtual memory          (kbytes, -v) unlimited
file locks                      (-x) unlimited

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

Читал (в т.ч. в доках к libev/libevent) что бывает прилетают фантомные события на чтения. Короче, выставь на сокеты асинхронный режим.

true_admin ★★★★★
()
Ответ на: комментарий от nerdogeek

не понял при чём тут ulimit, но лимин на дескрипторы можно поднять если соединений много.

Так же посмотри dmesg, там бывают весёлые сообщения от фаервола типа упёрлось всё в кое-какие лимиты.

Если клиент повисает то значит до него данные не доходят. Это, кстати, дебажится tcpdump.

true_admin ★★★★★
()

а что boost::asio::async_write( socket_, ... ) возвращает? в смысле, нет ли ошибки?

может у тебя банально тырнет отваливается. или что-то там у тебя за сеть.

nanoolinux ★★★★
()

Попробуй сделать strace, чтобы посмотреть, в asio проблема, или нет.

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

Ошибки на записи нет (в евент хендлере). Есть зависание при чтении из сокета у клиента.
все происходит на локалхосте.

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

Так вот, периодически (очень редко) происходит зависание в socket_.receive() на клиенте. ЧЯДНТ?

ссылка на вражий msdn, но там вроде толково все расписано:

http://msdn.microsoft.com/en-us/library/windows/desktop/ms738547(v=vs.85).aspx

с asio не работал, потому не знаю насколько актуально

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

The only working way to do that (that I have found) is to:

prevent accept() from adding more clients

have a list of the open sockets somewhere and to wait until they are all properly closed which means:

using shutdown() to tell the client that you will no longer work on that socket

call read() for a while to make sure that all the client has sent in the meantime has been pulled

then using close() to free each client socket.

THEN, you can safely close() the listening socket.

альтернативная версия, у меня так и сделано, но без asio, подвисаний нет, тестировал через apache benchmark

wota ★★
()
Ответ на: комментарий от nerdogeek

Какие нах асинхронные режимы, если речь про синхронное чтение?

Автор, повторяю, сделай strace, там будет видно, что происходит. Там будет recv или read, увидишь, пришли ли данные, или же нет. То есть увидишь, где проблема - в asio и твоем коде, или нет.

p.s. code review:

boost::asio::async_write( socket_, boost::asio::buffer( ss2.str() ),
Это фэйл, т.к. временный ss2.str() может быть разрушен раньше, чем состоится запись в сокет.

ratatosk
()
Ответ на: комментарий от ratatosk
std::string s("abc");
boost::asio::const_buffers_1 buf = boost::asio::buffer(s);
s[1] = 'w';
const void* p = boost::asio::buffer_cast<const void*>(buf); 
std::cout << static_cast<const char*>(p) << std::endl;

С ужасом для себя увидел: «awc»

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

Логично, asio буфер - это просто пара указатель + размер. Если бы он копировал, это было бы малопригодно для серьезного применения.

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

Нашел истинную причину зависания. Там реально нетривиальная трабла с асинхронным i/o.
Могу рассказать подробнее.

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

у меня там 2 процесса общаются через сокет.
первый процесс кидает в сокет реквест, потом ждет респонса от второго.
Проблема в том, что я инициировал асинхронную операцию записи в сокет, а только затем чтения. Так вот, второй процесс может респонс отослать быстрее чем первый закинет асинхронную операцию чтения этого респонса.
А буст то ли выкидывает, то ли игнорит не зарегестрированные евенты в еполле. Поэтому когда в еполле регеца этот эвент, то уже поздно.
Реализация с синхронной записью, затем синхронным чтением на сокете, который сконструирован с параметром io_service та же самая беда, причем разруливается она переходом на асинхр. операции i/o и правильной последовательностью регистрации этих евентов в бусте.
Хз, писать чувакам из boost.org, или нет...

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

Пиши, но сначала попробуй до минимального примера сократить.

Вот синхронный пример, передающий туда-сюда строчку, клиент посылает запрос, затем спит секунду, а затем читает ответ. Работает, как часы.

https://gist.github.com/4665157

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

Короче говоря, мне кажется, что косяк всё-таки где-то у тебя, или буст очень старый, там в asio было довольно-таки много проблем.

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

по сравнению с твоим примером у меня сервер асинхронно читает/пишет (но это скорее всего и не важно), а клиент - многопоточный, т.е. у меня несколько потоков, которые выполняют io_service.run()
Буду писать простой пример, чтобы бага воспроизводилась и слать репорт. Проверял только в boost 1.48.

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

А что в плане asio фонтан? А то у нас юзается 1.49 под Win- пока вроде норм, но хотелось бы услышать success/fail stories.

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

Да можно в трекере посмотреть (который, похоже, лежит...)

С 1.51 и 1.52 проблем вроде не было, до этого долго на 1.47 сидели. Соседний отдел весьма высоконагруженный сервак с 1.49 сейчас собирают.

По поводу винды - не скажу, только под linux/*bsd/solaris/macos используем.

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

Ему и не нужно быть thread-safe. Как и, например, std::vector'у.

ratatosk
()
18 апреля 2014 г.

Столкнулся с этой проблемой, хотелось бы узнать чем закончилась эта история, решилась ли проблема в новых версиях буста?

vasechkin
()

Были запущены 2 процесса на локалхосте, один - в роли сервера, второй - клиент. Клиент инициировал соединение с сервером. Сценарий работы был следующий: клиент писал в сокет асинхронно, а затем читал респонс синхронно. На чтении периодически всё подвисало потому что не приходил респонс, хотя сервер его отсылал (по логам видно).
Решил избавиться от постоянного создания соединения между клиентом и сервером. Решил просто использовать пул соединений, т.е. коннектился к серверу заранее и держал соединения до завершения работы клиента. Помогло. Всё работает на линуксах и бсд норм.
«клиент»: https://github.com/abudnik/prun/blob/master/src/worker/worker.cpp
«сервер»: https://github.com/abudnik/prun/blob/master/src/worker/exec.cpp
Предположительно проблема была в том, что когда сервер отсылал респонс (а точнее приходило событие об успешном копировании отсылаемого сообщения в буферы ядра), он тут же разрывал соединение (закрывал сокет) по своей инициативе, хотя это должен был делать сам инициатор (клиент). Клиент мог регестрировать событие на чтение в epoll уже когда сокет был закрыт сервером, поэтому (?) респонсы не доходили.

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

в начале теме была вроде речь об //async_read_some но, раз проблема была в синхронной задержке то это всё объясняет

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