A folyamatok közötti kommunikációs megoldások igen sokszÃnűek lehetÅ‘ségek és megvalósÃtás tekintetében. Azonban ezek csak a kommunikáció módját biztosÃtják alacsony szinten, viszont azt nem, hogy mit és hogyan is küldjünk és fogadjunk. Ez logikus is egészen addig, amÃg egy operációs renszeren belüli kommunikációról beszélünk, de mi a helyzet akkor, ha a gép határait át szeretnénk lépni?
Ebben az esetben szükségünk van egy kommunikációs sémára, protokollra a kliens és a fogyasztók között. A szakirodalom az ilyen protokollokat Remote Procedure Call, vagy röviden RPC protokolloknak nevezi. Ezek története egyidÅ‘s az internettel és mondhatni a különbözÅ‘ protokollok jönnek-mennek. Jelenleg azonban a JSON formátum népszerűségébÅ‘l adódóan kézenfekvÅ‘ ezt is JSON alapon lebonyolÃtani.
Itt jön képbe a JSON RPC, ami a korábbi RPC megoldásokkal szemben azzal az előnnyel rendelkezik, hogy ténylegesen fapados, de nem rossz értelemben. Nincs túlkomplikálva és pláne nem akar több lenni, mint egy RPC kommunikációs formátum.
Jelenleg a specifikációból két változat létezik, amelyek egymással nem kompatibilisek, vagy részben kompatibilisek. A 2.0-ás RFC1 számot is kapott. A specifikáció RFC 46272 számon érhető el, vagy a https://www.jsonrpc.org/specification oldalon elolvasható.
Ez alapján kedvenc JSON konvertálónkkal felvértezve elkészÃthetjük a saját implementációnkat, amire nem sok szükségünk van, hiszen a Microsoft a StreamJsonRpc NuGet csomagban3 ezt biztosÃtja számunka. A csomag nevében a Stream arra utal, hogy bármilyen Stream-et használó IPC megoldással kombinálható.
A példa kedvéért nézzünk meg egy Pipe alapú RPC megoldást.
using System;
using System.IO.Pipes;
using System.Threading.Tasks;
namespace JsonRpc.Server
{
internal class Api
{
public int Add(int n1, int n2)
{
return n1 + n2;
}
}
public static class Program
{
public static async Task ServeOneConnectionAsync()
{
var server = new NamedPipeServerStream("rpcPipe",
PipeDirection.InOut,
NamedPipeServerStream.MaxAllowedServerInstances,
PipeTransmissionMode.Byte,
PipeOptions.Asynchronous);
await server.WaitForConnectionAsync();
var rpc = StreamJsonRpc.JsonRpc.Attach(server, new Api());
await rpc.Completion;
}
public static async Task Main(string[] args)
{
Console.WriteLine("Server running. Press CTRL+C to exit");
while (true)
{
await ServeOneConnectionAsync();
}
}
}
}
A korábbi pipe-os IPC példához hasonlóan a szerver itt is egy NamedPipeServerStream segÃtségével hozza létre a Pipe-ot. Különbség annyi, hogy ki-és bemeneti konfigurációt kap, mivel a JSON RPC kétirányú kommunikáció. Küldünk egy JSON dokumentumot, amire JSON dokumentum választ kapunk. A PipeTransmissionMode.Byte és PipeOptions.Asynchronous konfiguráció fontos, mivel a JSON dokumentumok UTF-8 kódolást használnak, ami nem egyezik meg az UTF-16 kódolással, amit a C# string tÃpusa használ. Az aszinkron módra pedig a kód felépÃtése miatt van szükségünk.
Az Attach metódussal tudunk társÃtani egy osztályt a Pipe-hoz. Ennek az osztálynak a publikus metódusait tudjuk RPC segÃtségével meghÃvni. Az rpc.Completion taskra várakozással pedig biztosÃtjuk, hogy a klienshez eljusson az adat.
using System;
using System.IO.Pipes;
using System.Threading.Tasks;
namespace JsonRpc.Client
{
public static class Program
{
public static async Task Main(string[] args)
{
var client = new NamedPipeClientStream(".",
"rpcPipe",
PipeDirection.InOut,
PipeOptions.Asynchronous);
await client.ConnectAsync();
using var rpc = StreamJsonRpc.JsonRpc.Attach(client);
int sum = await rpc.InvokeAsync<int>("Add", 3, 5);
Console.WriteLine($"Add(3, 5): {sum}");
Console.ReadKey();
}
}
}
A kliens hasonlóan csatlakozik, majd az InvokeAsync metódussal meghÃvjuk a szerver Add metódusát, ami a szerveren az Api osztályban van. Ez egy generikus metódus, vagyis a JSON hÃvás eredményének deszerializálását is elvégzi a metódus.
A program kimenete:
Add(3, 5): 8
-
Az RFC (az angol Request For Comments rövidÃtése, magyarul: kéretik megkritizálni) egy olyan dokumentum, mely egy új Internet-szabvány beiktatásakor adnak közre. Az új szabvány elsÅ‘ tervezete saját számmal kerül a nyilvánosság elé, egy adott idÅ‘tartamon belül bárki hozzászólhat. Ezeket a hozzászólásokat rendszerezik, majd többszöri módosÃtás után a szabványtervezetet elfogadják, vagy eldobják. – Wikipedia↩