2009-09-29 3 views
1

У меня есть следующая проблема. Я хочу сделать несколько запросов на несколько «удаленных» серверов (на самом деле, мы контролируем ферму серверов). Соединение очень простое. Отправьте строку, а затем прочитайте строки назад. Из-за количества запросов и количества серверов я использую pthreads, по одному для каждого запроса.Простая библиотека ввода/вывода сети C/C++

Наивный подход, используя блокирующие сокеты, не работает; очень редко, у меня будет нить, застрявшая в «connect». Я не могу использовать SIGALRM, потому что я использую pthreads. Я попытался преобразовать код в O_NONBLOCK, но это значительно усложнило код для чтения отдельных строк.

Какие у меня варианты? Я ищу самое простое решение, которое позволяет следующий псевдокод:


// Inside a pthread 
try { 
    req = connect(host, port); 
    req.writeln("request command"); 
    while (line = req.readline()) { 
     // Process line 
    } 
} catch TimeoutError { 
    // Bitch and complain 
} 

Мой код в C++ и я использую Boost. Быстрый взгляд на Boost ASIO показывает мне, что это, вероятно, не правильный подход, но я мог ошибаться. ACE далеко, слишком тяжелый, чтобы решить эту проблему.

+0

Почему Boost ASIO ошибочно подходит? Я согласен с ACE (и если он не был обновлен, чтобы использовать современные идиомы C++, я бы предпочел избежать этого на этой основе!). –

+0

Я думаю, что Boost ASIO - неправильный подход, потому что он, похоже, не поддерживает таймауты при подключении или чтении/записи. Я ошибаюсь? Стандартный подход, похоже, заключается в использовании SIGALRM, который кажется неуместным, учитывая мое широкое использование pthreads. – ChrisInEdmonton

+0

Вопрос о одном потоке на разъем в стороне, что случилось с pthread-kill()? – Duck

ответ

5

Я видел комментарии, и я думаю, что вы можете использовать повышение :: ASIO с усилением :: ASIO :: deadline_timer

Фрагмент кода:

void restart_timer() 
    { 
     timer_.cancel(); 
     timer_.expires_from_now(boost::posix_time::seconds(5)); 
     timer_.async_wait(boost::bind(&handleTimeout, 
     MyClass::shared_from_this(), boost::asio::placeholders::error)); 
    } 

Где handleTimeout является функцией обратного вызова, timer_ является повышение :: ASIO :: deadline_timer и MyClass аналогичен

class Y: public enable_shared_from_this<Y> 
    { 
    public: 

    shared_ptr<Y> f() 
    { 
     return shared_from_this(); 
    } 
    } 

Вы можете позвонить restart_timer Перед подсоединением оу чтения/записи

Больше information о share_from_this()

+0

Я потратил некоторое время на преобразование своего кода, чтобы увеличить asio, и он действительно работает хорошо. Кажется, что асинхронные таймеры ввода/вывода и таймеры времени делают то, что мне нужно, и мой код теперь кажется стабильным. Взял немного переписывания за кулисами, но остальная часть моего кода почти не изменилась. – ChrisInEdmonton

6

Вы смотрели на Libevent?

http://www.monkey.org/~provos/libevent/

Это совершенно другая парадигма, но производительность настолько удивительно.

memcached построен на основе libevent.

+0

libevent - хорошая идея, я сейчас буду читать, чтобы узнать, подходит ли мне больше всего для моих нужд. – ChrisInEdmonton

0

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

1

Вы упомянули, что это происходит «очень изредка». Ваша сторона подключения должна иметь отказоустойчивость и обработку ошибок, которые вы ищете, но вы также должны учитывать стабильность ваших серверов, DNS, сетевых соединений и т. Д.

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