一般远程接口调用的服务都是基于客户端主动调用服务端,由服务端来提供相关的接口服务;在新版本的XRPC中引入了一个新的功能,即接口双向通讯,组件提供服务创建客户会话的接口代理并调用客户提供的接口服务。接下来介绍如何通过XRPC来使用接口双向通讯的应用,并实现服务端调用WFP/WINFROM这些客户端的本地方法。

引用组件

组件提供两个包分别是:BeetleX.XRPCBeetleX.XRPC.Clients;前者是在.net core上使用,而后者则提供给WFP/WINFROM使用.在0.8.2.3版本开始支持接口双向调用功能。

使用

组件是以接口作为基础通讯单元,所以必须以接口的方式来描述服务调用逻辑。接下来实现一个简单的接口,客户端向服务调用注册方法,服务端在接受客户注册后创建一个会话代理并调用获取客户端的时间。接口定义如下:

    public interface IUser
{
Task Login(string name); Task<DateTime> GetTime();
}

接口比较简单分别是LoginGetTime,接下来会分别在服务端和客户端实现这一接口,并进行一个双向调用。

服务端实现

    [Service(typeof(IUser))]
public class Program : IUser
{
static void Main(string[] args)
{
var builder = new HostBuilder()
.ConfigureServices((hostContext, services) =>
{
services.UseXRPC(s =>
{
s.ServerOptions.LogLevel = BeetleX.EventArgs.LogType.Warring;
s.ServerOptions.DefaultListen.Port = ;
s.RPCOptions.ParameterFormater = new JsonPacket();//default messagepack
},
typeof(Program).Assembly);
});
builder.Build().Run();
} public Task<DateTime> GetTime()
{
return DateTime.Now.ToTask();
} public Task Login(string name)
{
Console.WriteLine($"{name} login");
var token = XRPCServer.EventToken;
Task.Run(async () =>
{
IUser user = token.Server.GetClient<IUser>(token.Session);
while (true)
{
var time = await user.GetTime();
Console.WriteLine($"{name}[{token.Session.RemoteEndPoint}] time is:{time}");
//await Task.Delay(1000);
}
});
return Task.CompletedTask;
}
}

代码比较简单,在登陆方法中创建一个异步方法,并在方法中创建一个IUser针对当前会话的一个代理,然后循环调用客户端方法获取相应的时间。

客户端实现

    class Program : IUser
{
static XRPCClient client;
static void Main(string[] args)
{
client = new XRPCClient("192.168.2.18", );
client.PingTimeout = ;
client.Options.ParameterFormater = new JsonPacket();
client.Register<IUser>(new Program());
var user = client.Create<IUser>();
user.Login("henry");
System.Threading.Thread.Sleep(-);
} public Task<DateTime> GetTime()
{
return Task.FromResult(DateTime.Now);
} public Task Login(string name)
{
return Task.CompletedTask;
}
}

比起服务端,客户端所需要的代码就更简单了;通过XRPCClient.Create注册相关接口的本地实现类。只要客户端调用user.Login("henry");后服务端就是不停地向客户获取时间。通过运行程序可以看到以下运行结果:

以上完整代码可以从以下连接获取: https://github.com/IKende/BeetleX-Samples/tree/master/XRPC.InterfaceTwoWay

聊天服务

上面已经描述了接口双向调用的便利性,接下来通过接口双向调用快速地实现一个聊天服务。

    public interface IUser
{
Task Login(string name); Task Talk(string name, string message); Task Exit(string name);
}

以上是一个用户聊天的行为接口,分别是登陆、退出和发送消息。接下来通过服务端和客户端实现这一接口即可完成一个简单的聊天服务。

服务端实现

    [EventNext.Service(typeof(IUser))]
public class UserImpl : IUser
{
public Task Exit(string name)
{
return Task.CompletedTask;
} public Task Login(string name)
{
var token = XRPCServer.EventToken;
token.Session.Name = name;
foreach (var session in token.Server.Server.GetOnlines())
{
if (!string.IsNullOrEmpty(session.Name))
{
IUser user = token.Server.GetClient<IUser>(session);
user.Login(name);
}
}
return Task.CompletedTask;
} public Task Talk(string name, string message)
{
var token = XRPCServer.EventToken;
if (string.IsNullOrEmpty(token.Session.Name))
{
throw new Exception("登陆无效!");
}
foreach (var session in token.Server.Server.GetOnlines())
{
if (!string.IsNullOrEmpty(session.Name))
{
IUser user = token.Server.GetClient<IUser>(session);
user.Talk(session.Name, message);
}
}
return Task.CompletedTask;
}
}

服务端主要实现了两个方法,分别是登陆和发送消息;两个方法的都基本一样,在方法调用里面获取所有会话的IUser代理,并执行相关方法即可。为什么Exit这个方法没有实现呢,主要是服务通过监听连接断开事件进行处理,代码如下:

        static void Main(string[] args)
{
var builder = new HostBuilder()
.ConfigureServices((hostContext, services) =>
{
services.UseXRPC(s =>
{
s.ServerOptions.LogLevel = BeetleX.EventArgs.LogType.Debug;
s.ServerOptions.DefaultListen.Port = ;
s.RPCOptions.ParameterFormater = new JsonPacket();//default messagepack
s.RPCDisconnect += (o, e) =>
{
foreach (var session in e.Server.GetOnlines())
{
if (session != e.Session && !string.IsNullOrEmpty(session.Name))
{
IUser user = s.GetClient<IUser>(session);
user.Exit(e.Session.Name);
}
}
};
},
typeof(Program).Assembly);
});
builder.Build().Run();
}

这样一个简单的聊天服务就完成,接下来看一下客户端同样实现这一接口来完成功能。

客户端实现

    /// <summary>
/// MainWindow.xaml 的交互逻辑
/// </summary>
public partial class MainWindow : Window, IUser
{
public MainWindow()
{
InitializeComponent();
}
public Task Login(string name)
{
AddMessage(name, "login");
return Task.CompletedTask;
}
public Task Exit(string name)
{
AddMessage(name, "exit");
return Task.CompletedTask;
}
public Task Talk(string name, string message)
{
AddMessage(name, message);
return Task.CompletedTask;
}
private BeetleX.XRPC.Clients.XRPCClient mClient;
private IUser mUser;
private void Window_Loaded(object sender, RoutedEventArgs e)
{
mClient = new BeetleX.XRPC.Clients.XRPCClient("192.168.2.18", );
mClient.Options.ParameterFormater = new JsonPacket();
mClient.Register<IUser>(this);
mUser = mClient.Create<IUser>();
txtMessages.Document.Blocks.Clear();
}
private async void CmdLogin_Click(object sender, RoutedEventArgs e)
{
try
{
if (string.IsNullOrEmpty(txtName.Text))
{
MessageBox.Show("请输入登录名称!");
return;
}
await mUser.Login(txtName.Text);
MessageBox.Show("登陆成功!");
}
catch (Exception e_)
{
MessageBox.Show(e_.Message);
}
}
private async void CmdTalk_Click(object sender, RoutedEventArgs e)
{
try
{
await mUser.Talk(null, txtTalk.Text);
}
catch (Exception e_)
{
MessageBox.Show(e_.Message);
}
}
}

以上是一个WPF窗体的实现,代码功能是不是很简单,通过远程方法调用,服务端可以直接调用客户端窗体的方法代码。接下来看一下实际运行效果:

这样一个简单了聊天服务就完成了,看上去是不是非常简单;如果需要下载示例的完整代码可以访问: https://github.com/IKende/BeetleX-Samples/tree/master/XRPC.WFPChat

通过接口双向调用的功能,你可以实现更简单的通讯应用开发,因为你再也不需要定义消息标记来区分处理行为,可以大大地提高开发效率。

 

XRPC之接口双向调用的更多相关文章

  1. 如何让Java和C++接口互相调用:JNI使用指南

    如何让Java和C++接口互相调用:JNI使用指南 转自:http://cn.cocos2d-x.org/article/index?type=cocos2d-x&url=/doc/cocos ...

  2. 【转】java通用URL接口地址调用方式GET和POST方式

    java通用URL接口地址调用方式GET和POST方式,包括建立请求和设置请求头部信息等等......... import java.io.ByteArrayOutputStream; import ...

  3. 如何记录selenium自动化测试过程中接口的调用信息

    上一篇博客,我写了python自动化框架的一些知识和粗浅的看法,在上一篇中我也给自己提出一个需求:如果记录在测试过程中接口的调用情况?提出这个需求,我觉得是有意义的.你在测试过程中肯定会遇到一些莫名其 ...

  4. 在Winform混合式框架中整合外部API接口的调用

    在我们常规的业务处理中,一般内部处理的接口多数都是以数据库相关的,基于混合式开发的Winform开发框架,虽然在客户端调用的时候,一般选择也是基于Web API的调用,不过后端我们可能不仅仅是针对我们 ...

  5. SAP接口的调用

    最近做一个专案用到的SAO接口的调用,用到的上传参数获取回传的IRfcTable,以及以IRfcTable作为参数上传SAP,通过查阅很多资料,发现资料说明的也多是鱼龙混杂,许多没有实现就直接贴在上面 ...

  6. sso接口的调用

    之前一直想sso接口已经写好了,登录注册功能是怎么调用的呢?原来在登录注册的jsp页面实现的接口的调用,页面的校验和验证功能在jsp页面即可实现. 注册页面: <%@ page language ...

  7. COM组件 IDispatch 及双接口的调用

    转自:http://blog.csdn.net/cnhk1225/article/details/50555647 一.前言 前段时间,由于工作比较忙,没有能及时地写作.其间收到了很多网友的来信询问和 ...

  8. 【转载】COM 组件设计与应用(十一)—— IDispatch 及双接口的调用

    原文:http://vckbase.com/index.php/wv/1236.html 一.前言 前段时间,由于工作比较忙,没有能及时地写作.其间收到了很多网友的来信询问和鼓励,在此一并表示感谢.咳 ...

  9. 微信接口出现“调用支付jsapi缺少参数appid”

    微信接口出现“调用支付jsapi缺少参数appid” 注意:@Html.Raw(ViewBag.wxJsApiParam),//json串ViewBag.wxJsApiParam是一个在后台拼的一个j ...

随机推荐

  1. UITableView 刷新问题

    遇到的问题: 在程序里异步请求服务器后回调函数中处理数据和界面数据的刷新,但是更新UITableView的时候总是很慢才更新完,打印TableView的代理方法也都很快打印. 解决办法就是: [sel ...

  2. PageProxy分页的实现

    PageProxy是Ext.Net实现的一种分页方式,PageProxy通过实现OnReadData事件来完成分页. <ext:Store runat=" OnReadData=&qu ...

  3. H3C Comware的作用

  4. MVC插件式开发平台

    ---恢复内容开始--- 经过DyOS.BraveOS1.0再到BraveOS2.0,系统现在已经开发了下载. 我们的目标是,网页版操作系统,可以在线安装更新软件,并提供二次开发平台,提供基础的逻辑和 ...

  5. Fragment开发实战(二)

    由于在Android的实现机制中Fragment和Activity会被分别实例化为两个不相干的对象,他们之间的联系由Activity的一个成员对象Fragmentmanager来维护.Fragment ...

  6. 洛谷P1981 表达式求值 题解 栈/中缀转后缀

    题目链接:https://www.luogu.org/problem/P1981 这道题目就是一道简化的中缀转后缀,因为这里比较简单,只有加号(+)和乘号(*),所以我们只需要开一个存放数值的栈就可以 ...

  7. mybatis 逆向工程(通过数据库表针对单表自动生成mybatis执行所需要的代码)

    mybatis需要程序员自己编写sql语句,mybatis官方提供逆向工程,可以针对单表自动生成mybatis执行所需要的代码(mapper.java.mapper.xml.pojo…),可以让程序员 ...

  8. tf.variable_scope 参数

    最近在看TensorFlow的变量管理,发现很多代码中tf.variable_scope()参数的数量及意义还不太清楚,特此记录: def __init__(self, name_or_scope, ...

  9. [转]C#中 ??、 ?、 ?: 、?.、?[ ] 问号

    1. 可空类型修饰符(?) 引用类型可以使用空引用表示一个不存在的值,而值类型通常不能表示为空.例如:string str=null; 是正确的,int i=null; 编译器就会报错.为了使值类型也 ...

  10. mysql 第三课 jdbc基础操作

    jdbc连接可以大致分为5步: 1.注册驱动 2.获取连接 3.编写语句 4.执行语句 5.关闭连接 其中可以设置参数等等. 1.我们先建一个项目目录: 其中com.etc.dao为数据访问对象 co ...