Messagerie entre agents
Architecture de communication
Chaque agent expose un socket ZeroMQ PULL lié à un endpoint IPC :
Endpoint |
Usage |
|---|---|
|
Messages FIPA ACL applicatifs (transport local par défaut) |
|
Override pour déploiement multi-machine |
Les messages sont envoyés via des sockets PUSH persistants (PushCache),
un par destination, réutilisés entre les appels pour éviter le coût
de reconnexion.
Note
Le canal de contrôle interne de chaque agent (signaux de lifecycle)
utilise toujours une queue POSIX MQ /{8-char-id}. Seule la
messagerie FIPA ACL applicative passe par ZeroMQ.
Helpers de messagerie
Pour l’échange de messages ACL dans tes behaviours :
#include <gagent/messaging/AclMQ.hpp>
using namespace gagent::messaging;
// Pré-bind le socket PULL dans onStart() avant d'envoyer
void onStart() override {
acl_bind("monagent");
}
// Envoie un ACLMessage à l'agent "bob"
acl_send("bob", msg);
// Attend un message sur sa propre queue (timeout 5s)
auto opt = acl_receive("monagent", 5000);
if (opt) {
const ACLMessage& m = *opt;
// traitement...
}
Avertissement
Toujours appeler acl_bind(nom) dans onStart() avant tout
acl_receive(). Cela garantit que le socket PULL est lié avant que
l’autre agent n’essaie de s’y connecter.
Exemple complet : REQUEST ↔ INFORM
Voir tests/two_agents_acl.cpp pour un exemple fonctionnel.
Alice envoie 3 requêtes à Bob qui répond à chaque fois :
[Alice → Bob] REQUEST : "cycle 1"
[Bob → Alice] INFORM : "ok:1"
[Alice → Bob] REQUEST : "cycle 2"
[Bob → Alice] INFORM : "ok:2"
[Alice → Bob] REQUEST : "cycle 3"
[Bob → Alice] INFORM : "ok:3"
Pattern général d’un agent communicant
class ReceiverBehaviour : public Behaviour {
int count_ = 0;
public:
void onStart() override {
acl_bind("receiver"); // lie le socket PULL
}
void action() override {
auto opt = acl_receive("receiver", 5000);
if (!opt) return;
const ACLMessage& msg = *opt;
ACLMessage reply = msg.createReply(ACLMessage::Performative::INFORM);
reply.setSender (AgentIdentifier{"receiver"});
reply.setContent("ma réponse");
acl_send(msg.getSender().name, reply);
++count_;
}
bool done() override { return count_ >= 5; }
};
class SenderBehaviour : public Behaviour {
int count_ = 0;
public:
void onStart() override {
acl_bind("sender");
}
void action() override {
ACLMessage req(ACLMessage::Performative::REQUEST);
req.setSender (AgentIdentifier{"sender"});
req.addReceiver(AgentIdentifier{"receiver"});
req.setContent ("ma requête");
req.setConversationId("conv-" + std::to_string(count_));
acl_send("receiver", req);
auto opt = acl_receive("sender", 5000);
if (opt) ++count_;
}
bool done() override { return count_ >= 5; }
};
Déploiement multi-machine
Par défaut le transport est IPC (local). Pour connecter des agents sur des machines distinctes, définir la variable d’environnement avant de lancer l’agent destinataire :
# Machine B — agent "bob" écoute sur TCP
GAGENT_ENDPOINT_BOB=tcp://0.0.0.0:5555 ./mon_app
# Machine A — alice envoie à bob sur la machine B
GAGENT_ENDPOINT_BOB=tcp://192.168.1.42:5555 ./mon_app_alice
Note
Le nom dans la variable d’environnement est en majuscules :
GAGENT_ENDPOINT_<NOM_EN_MAJUSCULES>.
Thread-safety
PushCache est thread-safe : plusieurs behaviours d’un même agent
peuvent appeler acl_send() vers la même destination simultanément
sans risque de corruption. Le mutex est maintenu pour toute la durée
de l’envoi ZeroMQ.