Documente Academic
Documente Profesional
Documente Cultură
Integrarea bazată pe agenți de mesagerie care ar permite o comunicare asincronă dintre componentele
distribuite ale unui sistem (figura 1).
Sarcina lucrării
Agentul de mesaje este o componentă fizică care gestionează comunicarea dintre componentele unei
aplicații distribuite (figura 2). Avantajul utilizării acestei tehnici constă în decuplarea receptorului de
transmițătorul mesajelor. Prin urmare o aplicație participantă transmite mesaje doar agentului, indicând un
nume logic al receptorului.
Agentul poate expune diverse interfețe aplicațiilor în colaborare și poate transfera mesajele între acestea,
neimpunând o interfață comună tuturor participanților întru asigurarea interacțiunii. Responsabilitățile și
colaborările esențiale ale unui broker de mesaje sunt prezentate în tabelul de mai jos.
Responsabilități Colaborări
Expeditori: aplicații (componente) ce trimit mesaje
Primirea mesajelor
agentului
Receptorii: aplicații (componente) ce primesc mesaje
Determinarea destinatarilor și efectuarea rutării
de la broker
Tratarea diferențelor dintre interfețe
Transmiterea mesajelor
Desfășurarea lucrării
Pentru a realiza lucrarea dată de laborator s-a creat o aplicație formată din 3 componente principale ce
interacționează între ele. Componentele care participă la schimbul de mesaje sunt Broker-ul, Sender-ul și
Receiver-ul, numite în continuare aplicații. Astfel fiecare aplicație în parte va avea o funcție specială
2
individualizată de a scrie, citi sau retransmite mesajele din canalul de mesaje proiectat exclusiv pentru
funcționarea acestora.
Protocolul de transmisie prin care comunică aceste componente este UDP, pentru că nu avem necesitatea
de a păstra o conexiune permanentă între aceste componente. Totodată acesta nu verifică dacă pachetele au
ajuns la destinație, trimițând mai departe fluxul de biți către broker [1].
Brokerul fiind mediator dintre componentele distribuite, s-a decis folosirea unui șablon pentru
implementarea rutării mesajelor către aplicațiile necesare. Astfel s-a decis să se utilizeze șablonul Publish and
Subscribe. [2] În așa mod canalul dat difuzează un eveniment sau o notificare tuturor receptorilor abonați.
Prima componentă va fi transmițătorul care va transmite mesaje către Broker. Un factor important care
trebuie menționat aici este separarea și distribuirea componentelor, prin faptul că transmițătorul nu are legătură
directă cu receptorul, funcția de transmitere fiind lăsată pe baza brokerului. Crearea unui fir de execuție pentru
transmiterea fluxului de biți are loc în modul corespunzător:
Console.WriteLine("Sender...");
IOperation sender = new TransportService(new IPEndPoint(IPAddress.Parse("127.0.0.1"), 32123));
Din secvența de cod de mai sus putem observa metoda de creare a unui transmițător. Se creează un nou fir
de execuție cu ajutorul TPL. Transmițătorul se conectează la un punct de conexiune, format dintr-o adresă IP
și numărul unui port. Se creează un nou utilizator de tipul UserData și apelând metoda Auth() unde se introduc
parametrii necesari.
A doua componentă a sistemului distribuit va fi receptorul. Acesta va primi mesaje de la broker, neavând
legătură fizică cu transmițătorul. La fel acesta se conectează la un punct de acces care este constituit dintr-o IP
adresă și numărul portului la care vor fi trimise pachetele. Crearea unui fir de execuție pentru a lansa un receptor
are loc conform codului de mai jos:
Console.WriteLine("Receiver...");
IOperation receiver = new TransportService(new IPEndPoint( IPAddress.Parse("127.0.0.1"), 32123));
string m;
while ((m = await receiver.AsyncRead()) != "quit r")
{
Console.WriteLine(Environment.NewLine + m);
}
});
t.Wait();
Console.ReadLine();
La lansarea firului de execuție se va crea o variabila care va apela metoda ReceiverInfo() unde vor fi
introduse datele despre receptor. Cu ajutorul metodei AsyncWrite() se va transmite fluxul de date către broker.
Cum s-a menționat anterior mediatorul dintre transmițător și receptor este brokerul care este a treia
componentă a sistemului nostru. La lansarea aplicației broker se va crea un obiect de tipul IOperation inițializat
ulterior cu clasa BrokerService(). Interfața conține declararea metodelor ce vor fi folosite la transportul de biți
prin canalele de comunicare. La fel se va lansa un fir de execuție pentru broker, unde brokerul cu metoda
AsyncRead() va aștepta un flux de biți din canal pentru retransmiterea ulterioară a mesajului către destinatarul
concret din sistem. Așteptarea mesajelor va fi asincronă pentru a nu încărca funcționarea sistemul și stoparea
acestuia la un moment dat de timp din cauză frânării unui proces. Lansarea unui broker ca parte mediatoarea
dintre celelalte 2 componente are loc conform următoarei secvențe de cod:
Console.WriteLine("Broker...");
După cum am menționat anterior interfața IOperation conține 3 metode care vor fi implementate într-o altă
clasă fiind descrisă logica acestora. Declararea interfeței IOperation are loc în modul următor:
public interface IOperation
{
Task<string> AsyncRead();
Task AsyncWrite(string message);
Task AsyncReload();
}
4
constructor al acestei clase unde are loc conectarea obiectului de tip broker la un host. Metoda AsyncRead()
va primi o datagramă din canalul de mesaj pentru ca ulterior fluxul de biți să fie convertit in string pentru a
putea fi citit în mod natural. AsyncWrite() va prelua mesajul transmis din canalul de transmisie și-l va converti
in biți pentru a putea fi transmis mai departe la destinatar. Implementarea clasei pentru transmiterea informației
va arăta în felul următor:
public class TransportService : IOperation
{
private readonly UdpClient _trasport = new UdpClient();
Pentru ca brokerul să funcționeze acesta folosește clasa BrokerService care la fel implementează interfața
IOperation.
Mai jos sunt prezentate colecțiile care vor stoca mesajele, receptorii și mesajele care nu au putut fi transmise
la receptori. Toate acestea sunt colecții Thread Seif [3].
private readonly ConcurrentQueue<string> _messageQueue = new ConcurrentQueue<string
private readonly HashSet<ReceiverInfo> _receivers = new HashSet<ReceiverInfo>();
private readonly UdpClient _trasport;
public readonly ConcurrentQueue<string> UnreceivedList = new ConcurrentQueue<string>();
Totodată în clasa dată au fost implementate metodele interfeței. Logica acestor metode permite deja
brokerului să transmită, mesajele, să le puie in coada de așteptare și să înscrie un nou receptor pentru a fi posibil
ulterior de transmis mesaje acestuia.
Mesajele între componente se transmit în format XML, de aceea am realizat funcția DeserializeMessage()
care permite transformarea din formatul xml în obiecte de tip utilizator. Funcția de deserializare a mesajelor
poate fi reprezentată astfel:
5
private static void DeserializeMessage(string message, out UserData user)
{
var formatter = new XmlSerializer(typeof (UserData));
using (var stream = new MemoryStream())
{
var writer = new StreamWriter(stream);
writer.Write(message);
writer.Flush();
stream.Position = 0;
Dacă un receptor nu este disponibil la moment atunci mesajele ce trebuie transmise acestuia se introduc
într-o listă separată față de canalul unde se primesc toate mesajele [4]. Implementarea acestei proprietăți o
putem observa în secvența de cod de mai jos [5]. Tratarea mesajelor dacă nu este disponibil un receptor are loc
în modul următor:
var rc = _receivers.ToList().Find(x => x.Level == minLevel);
if (rc != null)
{
await _trasport.SendAsync(bytes, bytes.Length, rc.IpEndPoint);
_messageQueue.TryDequeue(out message);
}
else
{
UnreceivedList.Enqueue(mess);
_messageQueue.TryDequeue(out message);
}
6
Concluzii
Realizând acesta lucrare de laborator am realizat un agent mesagerie care permite o comunicare asincronă
dintre componentele distribuite ale unui sistem. Am însușit faptul că realizarea unui sistem distribuit presupune
concurență și asincronism pentru a nu crea blocări în momentul de transmitere sau procesarea a unor cereri.
Totodată distribuirea componentelor permite reducerea cuplării dintre ele, astfel transmițătorii comunică
doar cu brokerul, neștiind care sunt regulile de comunicarea cu receptorii. Crearea unui sistem distribuit
mărește integrabilitatea, în cazul nostru aplicația care comunică cu brokerul nu trebuie să prezinte aceeași
interfață. La rândul său brokerul poate deveni o punte dintre mai multe aplicații care au diferite interfețe, nivele
de securitate.
La fel dacă este vorba de un eșec al acestui sistem se reduc componentele unde ar putea exista o problemă,
și aceasta în cazul nostru este doar brokerul. Căderea acestuia implică blocarea activității întregului sistem.
7
Bibliografie
1. Dumitru Ciorbă. Indicații metodice Lab. 1. moodle.ati.utm.md. [Online] [Cited: Octombrie 12, 2016.]
https://moodle.ati.utm.md/pluginfile.php/5696/mod_book/chapter/1/labpad1.pdf.
4. Red Hat, Inc. Message Channel. https://access.redhat.com. [Online] [Cited: Octombrie 22, 2016.]
https://access.redhat.com/documentation/en-
US/Red_Hat_JBoss_Fuse/6.0/html/Implementing_Enterprise_Integration_Patterns/files/MsgSys-
MsgCh.html.
8
Anexa A
Codul sursă
Broker
using System;
using System.Threading.Tasks;
using Lab1_Pad;
namespace Broker
{
internal class BrokerProgram
{
private static void Main(string[] args)
{
Console.WriteLine("Broker...");
IOperation broker = new BrokerService();
Task t = Task.Factory.StartNew(async () =>
{
string message;
while ((message = await broker.AsyncRead()) != "quit b")
{
await broker.AsyncWrite(message);
await broker.AsyncReload();
Console.WriteLine(message);
}
});
t.Wait();
Console.ReadLine();
}
}
}
Receiver
using System;
using System.Net;
using System.Threading.Tasks;
using Lab1_Pad;
namespace Receiver
{
internal class ReceiverProgram
{
private static void Main(string[] args)
{
Console.WriteLine("Receiver...");
9
Console.ReadLine();
}
Sender
using System;
using System.Net;
using System.Threading.Tasks;
using Lab1_Lica_Pad;
namespace Sender
{
internal class SenderProgram
{
private static void Main(string[] args)
{
Console.WriteLine("Sender...");
IOperation sender = new TransportService(new
IPEndPoint(IPAddress.Parse("127.0.0.1"), 32123));
10
private static void BuildMessage(UserData user, out string message)
{
Console.Write("\nMin destination level: ");
Console.ForegroundColor = ConsoleColor.Green;
var sLevel = ushort.Parse(Console.ReadLine());
user.UserLevel = sLevel;
Console.ForegroundColor = ConsoleColor.Gray;
Console.WriteLine("Message: ");
Console.ForegroundColor = ConsoleColor.Green;
user.Message = Console.ReadLine();
message = UserData.SerializeUserData(user);
Console.WriteLine("\n=========================\n");
}
}
}
UserData
using System;
using System.IO;
using System.Runtime.Serialization;
using System.Xml.Serialization;
namespace Lab1_Pad
{
[Serializable]
public class UserData : ISerializable
{
public static int ClientLevel;
public UserData()
{
Username = "";
UserLevel = (ushort) ClientLevel;
Message = "";
}
//Deserialization constructor.
public UserData(SerializationInfo info, StreamingContext ctxt)
{
UserLevel = (ushort) info.GetValue("UserLevel", typeof (ushort));
Username = (string) info.GetValue("UserName", typeof (string));
Message = (string) info.GetValue("Messsage", typeof (string));
}
public string Username { get; set; }
public ushort UserLevel { get; set; }
public string Message { get; set; }
//Serialization function.
public void GetObjectData(SerializationInfo info, StreamingContext context)
{
info.AddValue("UserName", Username);
info.AddValue("UserLevel", UserLevel);
info.AddValue("Message", Message);
}
11
stream.Position = 0;
var sr = new StreamReader(stream);
message = sr.ReadToEnd();
}
return message;
}
}
}
XPlatform
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;
using System.Xml.Serialization;
namespace Lab1_Pad
{
public interface IOperation
{
Task<string> AsyncRead();
Task AsyncWrite(string message);
Task AsyncReload();
}
12
public readonly ConcurrentQueue<string> UnreceivedList = new
ConcurrentQueue<string>();//mes failed
public BrokerService()
{
_trasport = new UdpClient(32123);
}
Console.WriteLine(s);
UserData user;
DeserializeMessage(s, out user);
if (user.Message.Equals("subscribe"))
{
AddReceiver(rec, user);
return "";
}
_messageQueue.Enqueue(s);
return s;
}
if (rc1 != null)
{
13
await _trasport.SendAsync(bytes, bytes.Length, rc1.IpEndPoint);
var mess1 = mess;
UnreceivedList.TryDequeue(out mess1);
Console.WriteLine("Resending was done successfull!!!");
}
else
{
Console.WriteLine("Failed!!");
}
}
}
14
Anexa B
Screenshot-uri
15