بعد أن رأينا كيف ننشئ عملاء JADE و كيف نحدد المهام التي يقومون بها، لا يمكننا الحديث عن نظام متعدد العملاء multi agent system و ليس عن مجموعة عملاء يغرد كل في سربه إلا إذا كانت هناك تواصل و محادثة communication بين العملاء،
هذا المقال يقدم شرحا عن كيفية التواصل بين العملاء و كيفية بناء محادثات بينهم.
1. مقدمة:
لكي يستطيع عملاء JADE التعاون على أمر ما لا بد لهم من وسائل للتواصل بينهم، يملك كل عميل JADE صندوق بريدي يستقبل الرسائل المرسلة إليه، تكون هذه الرسائل في قائمة مرتبة حسب زمن وصولها.
2. تركيبة رسالة JADE
يستعمل عملاء JADE رسائل متوافقة مع معايير FIPA ACL (FIPA agent communication language) . هذه الرسائل عبارة عن instance من الصنف ACLMessage الموجود في الـ package المسمى jade.lang.acl .
تتكون رسائل JADE من التالي:
- مرسل الرسالة: يتم ملء هذه الخانة بطريقة آلية لدى إرسال الرسالة.
- مجموعة المستقبلين: يمكن إرسال نفس الرسالة إلى أكثر من عميل في آن واحد.
- communicative act : يمثل هدف العميل من إرسال الرسالة كإخبار العميل المستقبل بأمر ما، أو عمل call for proposal أو إرسال إجابة عن طلب ما ...
- محتوى الرسالة.
- إضافة إلى مجموعة من الخانات الأخرى مثل اللغة المستعملة في كتابة محتوى الرسالة، الـ timOut ،...
3. إرسال رسالة:
ليقوم عميل JADE بإرسال رسالة ما كل ما عليه هو ملء خانات رسالة JADE و من ثم استدعاء الدالة send الخاصة بالصنف Agent
المثال التالي يوضح كيفية إرسال رسالة إلى العميل المسمى said و يكون محتوى الرسالة ...salam :
- ACLMessage message = new ACLMessage(ACLMessage.INFORM);
- message.addReceiver(new AID("said", AID.ISLOCALNAME));
- message.setContent("salam…");
- send(message);
4. استقبال رسالة:
استقبال رسالة سهل مثل سهولة إرسال رسالة، بل أكثر من ذلك، فقط يكفي استدعاء الدالة receive() الخاصة بالصنف Agent
و ذلك كالتالي:
- ACLMessage messageRecu = receive();
أحيانا نحتاج إلى الرد على صاحب الرسالة، يمكن معرفة هوية المرسل باستعمال الدالة getSender() الخاصة بالصنف ACLMessage كالتالي:
- ACLMessage message = new ACLMessage(ACLMessage.INFORM);
- message.addReceiver(messageRecu.getSender());
- message.setContent("the response");
- send(message);
5. انتظار وصول رسالة:
في بعض الأحيان ، يمكن لعميل ما أن يقوم بتنفيذ مهمة معينة، لكن زمن تنفيذ المهمة مرتبط بزمن استقبال رسالة من agent معين.
من الممكن جدا جعل العميل ينتظر الرسالة بالطريقة التالية
- ACLMessage message =null ;
- While (message == null){
- Message = receive() ;
- }
- //المهمة الواجب القيام بها
لكن كما تلاحظون فإن هذا النوع من الانتظار يستهلك موارد كثيرة بحكم أن العميل ليس متوقفا كلية عن العمل و إنما "يقوم بالانتظار"
يوفر الصنف Behaviour دالة تسمح بإيقاف الـ behaviour إلى غاية استقبال رسالة
الدالة هي block() حيث أنه بمجرد استدعائها فإن الـ behaviour الحالي يتوقف و لا يكمل تنفيذه إلا بعد استقبال رسالة
- Message = receive() ;
- If (message == null) block();
- //المهمة الواجب القيام بها
تجب الإشارة هنا إلى أنه في حالة استقبال رسالة فإن كل الـ behaviours الخاصة بالـعميل و التي كانت متوقفة تواصل نشاطها
6. اختيار رسالة من صندوق البريد:
عندما يقوم العميل بالتواصل مع أكثر من عميل جملة واحدة، فإنه قد يحتاج في وقت معين ألا يستقبل إلا الرسائل القادمة من عميل معين أو التي تحقق شرطا معينا،
من أجل ذلك يقوم العميل بتعريف pattern للرسائل التي يود قراءتها و ذلك كالتالي:
- MessageTemplate template = MessageTemplate.MatchPerformative(ACLMessage.INFORM);
- ACLMessage msg = myAgent.receive(template);
7. مثال:
المثال التالي يوضح كيفية التواصل بين عميلين AgentA وAgentB
يقوم العميل AgentA بتوليد أرقام عشوائية و من ثم يرسلها إلى العميل AgentB
العميل AgentB يقوم بجمع هذه الأعداد
إذا لم يتجاوز المجموع حدا معينا (50) فإن العميل AgentB يخبر العميل AgentA بإنه لا يزال في إمكانه استقبال المزيد،
في حال ما إذا تجاوز المجموع 50 فإن العميل AgentB يرسل رسالة للـ AgentA ليوقف إرسال الرسائل و ينهي العميلان تنفيذهما.
كود العميل AgentA:
- import jade.core.AID;
- import jade.core.Agent;
- import jade.core.behaviours.FSMBehaviour;
- import jade.core.behaviours.OneShotBehaviour;
- import jade.lang.acl.ACLMessage;
- public class AgentA extends Agent {
- protected void setup(){
- FSMBehaviour agentA_beh= new FSMBehaviour();
- agentA_beh.registerFirstState(new waitingAgentB(), "waitingAgentB");
- agentA_beh.registerState(new SendingNumber(), "SendingNumber");
- agentA_beh.registerLastState(new end(), "end");
- agentA_beh.registerDefaultTransition("waitingAgentB", "SendingNumber");
- agentA_beh.registerTransition("SendingNumber", "waitingAgentB",0);
- agentA_beh.registerTransition("SendingNumber", "end", 1);
- addBehaviour(agentA_beh);
- }
- private class waitingAgentB extends OneShotBehaviour{
- @Override
- public void action() {
- block();
- }
- }
- /*****************************************************************/
- private class SendingNumber extends OneShotBehaviour{
- int valeurRetour = 0;
- @Override
- public void action() {
- ACLMessage messageRecu = receive();
- if (messageRecu.getContent().equalsIgnoreCase("ready") ) valeurRetour=0;
- else valeurRetour=1;
- ACLMessage message = new ACLMessage(ACLMessage.INFORM);
- message.addReceiver(messageRecu.getSender());
- message.setContent(chiffre+"");
- send(message);
- }
- public int onEnd(){
- return valeurRetour;
- }
- }
- /*****************************************************************/
- private class end extends OneShotBehaviour{
- @Override
- public void action() {
- myAgent.doDelete();
- }
- }
- }
كود العميل AgentB
- import java.security.acl.Acl;
- import jade.core.AID;
- import jade.core.Agent;
- import jade.core.behaviours.FSMBehaviour;
- import jade.core.behaviours.OneShotBehaviour;
- import jade.lang.acl.ACLMessage;
- public class AgentB extends Agent {
- int total = 0;
- boolean stop = false;
- protected void setup(){
- FSMBehaviour agentB_beh= new FSMBehaviour();
- agentB_beh.registerFirstState(new Waiting for number(), "Waiting for number");
- agentB_beh.registerState(new Display(), "Display");
- agentB_beh.registerState(new end(), "end");
- agentB_beh.registerTransition("Waiting for number", "Display",0);
- agentB_beh.registerTransition("Waiting for number", "end",1);
- agentB_beh.registerDefaultTransition("Display", "Waiting for number");
- addBehaviour(agentB_beh);
- }
- private class Waiting for number extends OneShotBehaviour{
- int valeurRetour = 0;
- public void action() {
- ACLMessage message = new ACLMessage(ACLMessage.INFORM);
- message.addReceiver(new AID("AgentA", AID.ISLOCALNAME));
- if(!stop){
- message.setContent("ready");
- send(message);
- valeurRetour=0;
- block();
- }else{
- message.setContent("done");
- send(message);
- valeurRetour=1;
- }
- }
- public int onEnd(){
- return valeurRetour;
- }
- }
- /**********************************************************************/
- private class Display extends OneShotBehaviour{
- @Override
- public void action() {
- ACLMessage messageRecu = receive();
- if (total > 50) stop = true;
- }
- }
- /**********************************************************************/
- private class end extends OneShotBehaviour{
- @Override
- public void action() {
- myAgent.doDelete();
- }
- }
- }

