2009-09-29 6 views
1

J'ai le problème suivant à résoudre. Je veux faire un certain nombre de demandes à un certain nombre de serveurs "distants" (en fait, une ferme de serveurs que nous contrôlons). La connexion est très simple. Envoyez une ligne, puis relisez les lignes. En raison du nombre de requêtes et du nombre de serveurs, j'utilise pthreads, un pour chaque requête.Bibliothèque d'E/S réseau simple C/C++

L'approche naïve, utilisant des douilles de blocage, ne fonctionne pas; très occasionnellement, je vais avoir un fil coincé dans 'connect'. Je ne peux pas utiliser SIGALRM parce que j'utilise pthreads. J'ai essayé de convertir le code en O_NONBLOCK mais cela compliquait énormément le code pour lire des lignes simples.

Quelles sont mes options? Je suis à la recherche de la solution la plus simple qui permet à l'pseudocode suivant:


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

Mon code est en C++ et j'utilise Boost. Un rapide coup d'œil à Boost ASIO me montre que ce n'est probablement pas la bonne approche, mais je peux me tromper. ACE est loin, beaucoup trop lourd pour résoudre ce problème.

+0

Pourquoi Boost ASIO est-il une mauvaise approche? Je suis d'accord avec ACE (et à moins qu'il n'ait été mis à jour pour utiliser des idiomes C++ modernes, je préfère l'éviter aussi sur cette base!). –

+0

Je pense que Boost ASIO est la mauvaise approche, car il ne semble pas prendre en charge les délais d'attente de connexion ou de lecture/écriture. Est-ce que je me trompe? L'approche standard semble être d'utiliser SIGALRM qui semble inapproprié compte tenu de mon utilisation intensive de pthreads. – ChrisInEdmonton

+0

La question d'un thread par socket de côté, quel est le problème avec pthread-kill()? – Duck

Répondre

5

J'ai vu les commentaires et je pense que vous pouvez utiliser boost :: asio avec boost :: asio :: deadline_timer

Fragment d'un code:

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)); 
    } 

Où handleTimeout est une fonction de rappel, timer_ est boost :: asio :: deadline_timer et MyClass est similaire à

class Y: public enable_shared_from_this<Y> 
    { 
    public: 

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

Vous pouvez appeler restart_timer avant lecture connect ou/écriture

Plus information à propos share_from_this()

+0

J'ai passé un peu de temps à convertir mon code pour booster asio et ça semble bien fonctionner. Les E/S de socket asynchrones et les minuteurs de délai semblaient faire ce dont j'avais besoin, et mon code est maintenant apparemment stable. J'ai pris un peu de réécriture dans les coulisses mais le reste de mon code est presque inchangé. – ChrisInEdmonton

6

Avez-vous regardé libevent?

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

Il est paradigme totalement différent, mais la performance est tellement incroyable.

memcached est construit sur libevent.

+0

libevent est une bonne idée, je vais lire à ce sujet maintenant pour voir si cela correspond mieux à mes besoins. – ChrisInEdmonton

0

Vous pouvez également fermer le socket à partir de l'autre thread. Cela devrait provoquer l'échec de la connexion.

1

Vous avez mentionné que cela se produisait «très occasionnellement». Votre côté 'connexion' doit avoir la tolérance aux pannes et la gestion des erreurs que vous recherchez mais vous devez également tenir compte de la stabilité de vos serveurs, DNS, connexions réseau, etc.

Les protocoles sous-jacents sont très robustes et fonctionnent très bien, Donc, si vous rencontrez ce genre de problèmes, il vaut peut-être mieux vérifier.

Questions connexes