JADE学习笔记4:Agent通信

来源:互联网 发布:c语言猜数游戏 编辑:程序博客网 时间:2024/06/05 10:59

Agent通信是JADE中最基本的功能,基于异步消息传递。每个Agent都有一个“邮箱”(Agent消息队列),JADE实时运行环境传递Agent发送的消息传递到邮箱内,通知接收Agent。Agent是否处理队列中的消息由Agent开发者决定。
消息格式遵循FIPA-ACL消息结构,每条消息包括以下几个内容:
  1)sender:消息的发送者,用Agent标志AID表示。
  2)receivers:接受Agent消息的Agent,可以是多个。
  3)Reply-to:应收到回应的接受者。
  4)Performative:通信行为或称通信原语,标志发送消息的目的,即发送者想要通过发送消息干什么。通常有这样一些常值:REQUEST,INFORM,ACCEPT_PROPOSAL,REJECT_PROPOSAL,PROPOSE等。如REQUEST表示发送者希望接收者执行一个特定的任务,INFORM表示发送者希望接收者了解一些事情,PROPOSE或者CFP(Call For Proposals)表示发送者希望进行一次谈判。
  5)Content:消息的内容。
  6)Language:内容语言,比如内容的编码格式。
  7)ontology:双方都能够理解的消息内容的概念说明和语义描述。
发送消息时调用send()方法,接收消息调用Receive()方法。

简单实例:
发送者:l_3_ACL_cyc文件夹中建立类文件Sender

package l_3_ACL_cyc;import jade.core.AID;import jade.core.Agent;import jade.core.behaviours.*;import jade.lang.acl.ACLMessage;public class Sender extends Agent{    public void setup() {        addBehaviour(new Behaviour() {            private boolean finished = false;            @Override            public void action() {                // TODO 自动生成的方法存根                doWait(5000);                ACLMessage acl=new ACLMessage(ACLMessage.INFORM); //通知                AID r=new AID();                r.setLocalName("Rec");  //设置接收Agent的本地名                acl.addReceiver(r);     //添加到ACL消息中                acl.setSender(getAID());  //设置发送者本地名,这里可以省略                acl.setContent("Hello,Rec"); //设置内容                send(acl);   //向Rec发送消息                System.out.println("local name is:" + getLocalName());                System.out.println(getLocalName()+" send Hello to Rec");                System.out.println("the content is : "+acl.getContent());                System.out.println("send finished");                doWait(5000);                  finished=true;                doDelete();            }            @Override            public boolean done() {                // TODO 自动生成的方法存根                return finished;            }        });    }}

接收者:l_3_ACL_cyc文件夹中创建类文件Receiver

package l_3_ACL_cyc;import jade.core.*;import jade.core.behaviours.*;import jade.lang.acl.ACLMessage;public class Receiver extends Agent {    public void setup() {        addBehaviour(new CyclicBehaviour() {            @Override            public void action() {                // TODO 自动生成的方法存根                ACLMessage acl1=receive();                if(acl1!=null) {                    System.out.println("receiving");                    doWait(2000);                    System.out.println(getLocalName()+" receive a message");                    System.out.println("the message is: "+acl1.getContent());                    System.out.println("the message is: "+acl1.getSender().getLocalName());                    doDelete();                }            }});    }}

运行时,通过-gui命令调出GUI管理器。start new Agent,先启动Receiver类,命名为Rec(必须与前面添加接收者时的命名保持一致);
再启动Sender类。

运行结果:

local name is:SendSend send Hello to Recthe content is : Hello,Recsend finishedreceivingRec receive a messagethe message is: Hello,Recthe message is from: Send

这里,ACLMessage接收消息是通过一个循环行为实现的,这样会占用较长CPU时间。我们也可以不用循环行为,通过block()方法,它的作用是阻塞行为,使Agent不再运行此行为。当新消息插入到消息队列中时,阻塞的行为被激活,再次执行处理接收的消息。
其代码如下,Sender类的建立方法与上述一样。

public class Receiver extends Agent{    public void setup() {        Behaviour b=new SimpleBehaviour() {            boolean finished=false;            @Override            public void action() {                // TODO 自动生成的方法存根                ACLMessage acl1=receive();                if(acl1!=null) {                    System.out.println("receiving");                    doWait(2000);                    System.out.println(getLocalName()+" receive a message");                    System.out.println("the message is: "+acl1.getContent());                    System.out.println("the message is: "+acl1.getSender().getLocalName());                    finished = true;                    myAgent.doDelete();                }                else {                    System.out.println(getLocalName()+" does not receive a message");                    block();//如果没有消息,则阻塞行为                }            }            @Override            public boolean done() {                // TODO 自动生成的方法存根                return finished;            }};            addBehaviour(b);    }}

接收者的代码流程为:添加一个简单行为,这一行为检查现在是否有受到消息,若没有,则执行block()方法组织目前的behaviour执行,直到有新的消息到达。

上述只是实现了消息的传递,我们往往希望能完成信息的交互。FIPA定义了一组交互协议,在jade.proto包中提供了多种常用交互协议的支持。
下面是一个稍复杂的基于交互协议的例子。Baz作为行为发起人,向Bob发出结婚请求,Bob接到信息后,回复,然后Baz接到回复并输出信息。

l_5_ACL_complex文件夹中建立类文件Name_Baz

package l_5_ACL_complex;import jade.core.AID;import jade.core.Agent;import jade.domain.FIPANames.InteractionProtocol;import jade.lang.acl.ACLMessage;import jade.proto.SimpleAchieveREInitiator;public class Name_Baz extends Agent {    static class MarriageProposer extends SimpleAchieveREInitiator{        protected MarriageProposer(Agent Agent, ACLMessage msg) {            super(Agent, msg);            }        //对Bob的回复做出响应        protected void handleAgree(ACLMessage msg) {  //Bob回复通信,输出函数            System.out.println(myAgent.getLocalName() + " said excitedly :  " +            msg.getSender().getLocalName()            + "has agreed to marry me !");            }        protected void handleRefuse(ACLMessage msg) {//Bob回复拒绝,输出函数            System.out.println(myAgent.getLocalName() + " said sadly : Oh no! "            + msg.getSender().getLocalName() + " refused me .");            }        protected void handleInform(ACLMessage msg) {//Bob回复一段话,输出函数            System.out.println(myAgent.getLocalName() + " said :"                     + msg.getSender().getLocalName()+ " has informed me of the status of my request."                     + "They said : "+ msg.getContent());            }        protected void handleNotUnderstood(ACLMessage msg) {//Bob回复不理解请求,Baz输出            System.out.println(myAgent.getLocalName() + " said :" + msg.getSender().getLocalName()                    + " has indicated that they didn't understand.");            }        protected void handleOutOfSequence(ACLMessage msg) {  //Bob给了一个有误的回复            System.out.println(myAgent.getLocalName() + " said :" + msg.getSender().getLocalName()                    + "gave me an unexcepted answer");            }    }    public void setup() {        System.out.println(getLocalName() + ": about to propose marriage to Bob ");                doWait(3000); // wait for bob to be started.                ACLMessage msg = new ACLMessage(ACLMessage.REQUEST);                AID to = new AID();                to.setLocalName("Bob");                msg.setSender(getAID());                msg.addReceiver(to);                msg.setContent("Marry me!");                msg.setProtocol(InteractionProtocol.FIPA_REQUEST);                addBehaviour(new MarriageProposer(this, msg));    }}

l_5_ACL_complex文件夹中建立类文件Name_Bob

package l_5_ACL_complex;import jade.core.*;import jade.domain.FIPANames.InteractionProtocol;import jade.domain.introspection.AddedBehaviour;import jade.lang.acl.ACLMessage;import jade.lang.acl.MessageTemplate;import jade.proto.SimpleAchieveREInitiator;import jade.proto.SimpleAchieveREResponder;public class Name_Bob extends Agent{    static class MarriageResponder extends SimpleAchieveREResponder{  //准备答复        public MarriageResponder(Agent a) {            super(a, createMessageTemplate                    (InteractionProtocol.FIPA_REQUEST));            // TODO 自动生成的构造函数存根        }        private static final long serialVersionUID = 1L;        protected ACLMessage prepareResponse(ACLMessage msg) {            ACLMessage responder=msg.createReply() ;            if(msg.getContent()!=null&&msg.getContent().equals("Marry me!"))            {                System.out.println(myAgent.getLocalName()+": "+                            msg.getSender().getLocalName()+" has asked me to marry him");                AID r=msg.getSender();                if(r.getLocalName().equals("Baz")) {                    responder.setPerformative(ACLMessage.AGREE);                    System.out.println(myAgent.getLocalName()+": I am going to agree.");                }                else                 {                    responder.setPerformative(ACLMessage.REFUSE);                    System.out.println(myAgent.getLocalName()+": I am going to turn him down.");                }            }            else            {                responder.setPerformative(ACLMessage.NOT_UNDERSTOOD);                System.out.println("I did not understand what "+msg.getSender().getLocalName()+" said");            }            return responder;        }        protected ACLMessage prepareResultNotification (ACLMessage inmsg,ACLMessage outmsg) {  //最终答复            ACLMessage msg=inmsg.createReply();            msg.setPerformative(ACLMessage.INFORM);            msg.setContent("I do!");            return msg;        }    }    protected void setup() {        System.out.println(getLocalName()+" : I wonder if anybody would like to marry me!");        addBehaviour(new MarriageResponder(this));    }}

按照以前记载,先打开GUI管理器,GUI管理打开之后先建立一个名为Bob的Agent,对应的类为l_5_ACL_complex.Name_Bob,然后再建立一个名为baz的Agent,对应的类为l_5_ACL_complex.Name_Baz,顺序不能变,以下是输出结果:

Bob : I wonder if anybody would like to marry me!Baz: about to propose marriage to Bob Bob: Baz has asked me to marry himBob: I am going to agree.Baz said excitedly :  Bobhas agreed to marry me !Baz said :Bob has informed me of the status of my request.They said : I do!
原创粉丝点击