-
Notifications
You must be signed in to change notification settings - Fork 1
RPC Getting started
You need to create two classes: session factory & session.
Every time we will get a new connection we ask your factory for a new session. Factory is useful to pass some arguments to the session.
public class SessionFactory : ISessionFactory
{
public RpcSession CreateSession(RpcSessionContext sessionContext)
{
return new Session(sessionContext, context);
}
}Session is like a network connection, but with a feature to call the methods on the other side. It's gonna be active while your connection is active
Here the session have only one RPC method ReverseString and it will return a reversed string.
public class Session : RpcSessionImpl
{
public Session(RpcSessionContext sessionContext) : base(sessionContext)
{
}
[RemotingMethod]
string ReverseString(string message)
{
char[] charArray = message.ToCharArray();
Array.Reverse( charArray );
return new string( charArray );
}
}Next we need to create a server (you can use RpcUdpServer as well, but it's configuration a bit differs)
RpcTcpConfigurationServer configurationServer = new RpcTcpConfigurationServer();
configurationServer.LogManager = new LogManager(LogSeverity.INFO,
new LoggingHandlerConsole(new LoggingFormatterDefault()));
configurationServer.LogManagerNetwork = new LogManager(LogSeverity.INFO,
new LoggingHandlerConsole(new LoggingFormatterDefault()));
configurationServer.SessionFactory = new SessionFactory();
RpcTcpServer server = new RpcTcpServer(configurationServer);
server.Start();
server.Listen(10000); //Listen is a non blocking methodAnd we need a client to connect. In this example we will have same SessionFactory, and so Session, but you may have diffirent factories and sessions on different sides
RpcTcpConfigurationClient configurationClient = new RpcTcpConfigurationClient();
configurationClient.LogManager = new LogManager(LogSeverity.INFO,
new LoggingHandlerConsole(new LoggingFormatterDefault()));
configurationClient.LogManagerNetwork = new LogManager(LogSeverity.INFO,
new LoggingHandlerConsole(new LoggingFormatterDefault()));
configurationClient.SessionFactory = new SessionFactory();
RpcTcpClient client = new RpcTcpClient(configurationClient);
client.Start();
//this is gonna open a connection, and establish encryption channel (if set)
await client.OpenConnectionAsync("127.0.0.1", 10000);
//this will create a new RpcSession without authentication
//without starting session client will keep persistent connection,
//but client.Session will be null (same on the server)
//the initiator of starting session is always client
await client.StartSessionNoAuth();
//next we call a ReverseString and get it's results
string reversedString = await client.Session.ExecuteAsync<string, string>("ReverseString", "test");
Trace.Assert(reversedString == "tset");client.Session is a your RPC session, and it has two main ways to execute remoting method:
Executes remoting method and awaiting for the result (even it's a void method).
//to execute void methods without arguments
public virtual Task ExecuteAsync(int methodIdentity);
public virtual Task ExecuteAsync(string methodIdentity);
public virtual Task ExecuteAsync(int methodIdentity, ExecutionOptions options);
public virtual Task ExecuteAsync(string methodIdentity, ExecutionOptions options);
//to execute void methods with an argument
public virtual Task ExecuteAsync<A>(int methodIdentity, A arg);
public virtual Task ExecuteAsync<A>(string methodIdentity, A arg);
public virtual Task ExecuteAsync<A>(int methodIdentity, A arg, ExecutionOptions options);
public virtual Task ExecuteAsync<A>(string methodIdentity, A arg, ExecutionOptions options);
//to execute methods with return value without arguments
public virtual Task<R> ExecuteAsync<R>(int methodIdentity);
public virtual Task<R> ExecuteAsync<R>(string methodIdentity);
public virtual Task<R> ExecuteAsync<R>(int methodIdentity, ExecutionOptions options);
public virtual Task<R> ExecuteAsync<R>(string methodIdentity, ExecutionOptions options);
//to execute methods with return value with arguments
public virtual Task<R> ExecuteAsync<R, A>(int methodIdentity, A arg);
public virtual Task<R> ExecuteAsync<R, A>(string methodIdentity, A arg);
public virtual Task<R> ExecuteAsync<R, A>(int methodIdentity, A arg, ExecutionOptions options);
public virtual Task<R> ExecuteAsync<R, A>(string methodIdentity, A arg, ExecutionOptions options);ExecutionOptions:
-
Timeout- timeout in milliseconds after which you will get TimeoutException. If set - overridesDefaultExecutionTimeoutfrom configuration (default: -1|Infinite) -
State- a tag to keep add-on information in overloads (default: null) -
CancellationToken- cancellation token (Default: CancellationToken.None)
Keep in mind that cancelling operation or getting timeout exception doesn't mean this method won't be executed, it just means we don't want to wait for results anymore
Executes remoting method but no waiting for the completion, just waiting until send I/O operation completed
//to execute methods without argument
public virtual Task Send(int methodIdentity);
public virtual Task Send(string methodIdentity);
public virtual Task Send(int methodIdentity, SendingOptions sendingOptions);
public virtual Task Send(string methodIdentity, SendingOptions sendingOptions);
//to execute methods with an argument
public virtual Task Send<T>(int methodIdentity, T arg);
public virtual Task Send<T>(string methodIdentity, T arg);
public virtual Task Send<T>(int methodIdentity, T arg, SendingOptions sendingOptions);
public virtual Task Send<T>(string methodIdentity, T arg, SendingOptions sendingOptions);SendingOptions:
-
State- a tag to keep add-on information in overloads (default: null) -
ExpectResponse- if set true,OnRemoteExecutionExceptionwill trigger in case remote method exceptions (default: false) -
Channel(only for UDP) - channel to send remoting request (default: UdpConnection.DEFAULT_CHANNEL) -
DeliveryType(only for UDP) - delivery type of remoting request (default: DeliveryType.ReliableOrdered)
By the server side you can use Execute/Send as well
By default methods are identified by it's name, but you can override this setting in remoting method attribute:
[RemotingMethod] //method identified by it's name
[RemotingMethod(1)] //method identified by index
[RemotingMethod("new_name")] //method identified by custom nameyou can mix int and string identification, just be sure you don't have two methods with the same id
- Method must have zero or one argument with one of the supporting types
- Method must be void or return one of the supporting types (non-void only if allowed by
configuration.RemotingInvocationRules) - Method can be
asyncand returnTaskorTask<>(if allowed byconfiguration.RemotingInvocationRules) - Method may be non-public only if allowed by
configuration.RemotingInvocationRules
RpcTcpServer, RpcUdpServer, RpcUdpClient, RpcTcpClient have events and protected virtual methods:
-
OnSessionOpened- called when session established and ready -
OnSessionClosed- called when session closed. Usually session bound to the connection, so if the connection closed the session closed as well.
RpcUdpClient, RpcTcpClient have events and protected virtual methods:
-
OnStatusChanged- called when client status has changed
All the calls of events and RPC methods are synchronized with your context (if set), see more
Any exception raised inside of the scope of calling remote method is wrapped in RemoteException. You also can throw RemoteException directly
UDP works very similar to TCP, it just gives you some options how to Send rpc calls in SendingOptions
UDP classes: RpcUdpClient, RpcUdpServer