远程调用原理初探(附c#代码示例)

分布式系统有很多成熟的解决方案。如:微软的WCF。WCF太过于复杂,配置也麻烦。其实可以自己动手设计一个小的分布式系统。系统的原理完全在自己掌握之中,可以根据业务随机而变。这里展示远程调用最核心最基本的处理逻辑,其实远程调用并不复杂神秘。

分布式系统其实是数据流的交换。数据必须快速的从一段传送到另一端,否则系统性能就大打折扣。对于.net,本人设计一个非常优化易于使用的网络库(EasyNetMessage)。使用该库,不需要关心底层细节,所有处理对象是string、byte;发送时,不需要处理分包(几十M的数据也可以一次发送);收包时,不需要处理粘包。本文所示例代码,就是基于该网络库。本文章实例代码见底部。

实现目标

实现一个非常简单的应用   internal int AddCall(int value1, int value2);就是两个整数相加。调用过程和本地完全一样,只是执行加法操作是在远程服务器实现的。操作非常简单,但是揭示了远程调用的核心处理流程。

处理过程:

a) 数据发送

  每次函数调用必须有一个唯一标识CallId,这个也是发包的唯一标识;服务端处理完后,返回的结果也带有此标识。通过此标识,将发送端数据和返回数据关联起来了。

  发送完数据后,客户端线程要挂起,等待服务器端的处理结果。线程挂起使用ManualResetEvent。并建立起CallId与ManualResetEvent的对应关系。当数据返回时,就能找到对应的ManualResetEvent。

  //callid与事件关联
        Dictionary<int, ManualResetEvent> _callEventGroup = new Dictionary<int, ManualResetEvent>();
        //callId与返回结果关联
        Dictionary<int, NetCallAddAck> _callResultGroup = new Dictionary<int, NetCallAddAck>();
        internal int AddCall(int value1, int value2)
        {
            //组织发送包
            NetCallAdd add = new NetCallAdd();
            add.Value1 = value1.ToString();
            add.Value2 = value2.ToString();

            MonitorClient client = GetCurAppClient();
            if (client == null)
                throw new Exception("socket未连接!");

            //生成线程事件,并与CallId关联
            ManualResetEvent callEvent = new ManualResetEvent(false);
            lock (_callEventGroup)
            {
                _callEventGroup.Add(add.CallId, callEvent);
            }

            //发送数据
            EN_SendDataResult result = _netServer.SendData(client.ClientSocket, add.ToEasyMessage().ToNetPacket());
            if (result != EN_SendDataResult.ok)
            {
                lock (_callEventGroup)
                {
                    _callEventGroup.Remove(add.CallId);
                }
                throw new Exception("网络发送异常!");
            }

            //等待结果
            callEvent.WaitOne(3000);
            _callEventGroup.Remove(add.CallId);

            //查看结果集
            lock (_callResultGroup)
            {
                if (_callResultGroup.ContainsKey(add.CallId))
                {
                    NetCallAddAck ack = _callResultGroup[add.CallId];
                    return int.Parse(ack.Result);
                }
            }

            throw new Exception("没有返回结果!");
        }

b)数据返回

数据返回后的处理是在另一个线程。数据返回后,先根据CallId查找对应的ManualResetEvent;如果找不到,有可能服务器处理太慢,超时了。

先将返回结果存储到哈希数组中,key为CallId。再调用ManualResetEvent的Set函数,唤醒调用端线程。调用端线程根据CallId到哈希表中获取结果。

        internal void OnRcvAck(NetCallAddAck addAck)
        {
            //根据callid找到事件
            ManualResetEvent callEvent = null;
            lock (_callEventGroup)
            {
                if (!_callEventGroup.ContainsKey(addAck.CallId))
                    return;
                callEvent =_callEventGroup[addAck.CallId];
            }

            //结果存放到哈希表中
            lock (_callResultGroup)
            {
                _callResultGroup.Remove(addAck.CallId);
                _callResultGroup.Add(addAck.CallId, addAck);
            }
            //设置事件为有信号,调用方挂起的线程可以继续执行
            callEvent.Set();
        }

进一步说明:可以在此基础上,进一步扩展。开发出类似Redis的内存库。客户端的调用也不一定是同步 ,可以采用异步回调的方式处理。其实如果知道处理的原理,可以根据自己的业务做裁剪。只有知其所以然,才能开发出最符合自己业务的系统,才可能进一步优化。

实例代码https://download.csdn.net/download/qq_29939347/10684858

原文地址:https://www.cnblogs.com/yuanchenhui/p/remoteCall.html

时间: 2024-08-30 12:29:01

远程调用原理初探(附c#代码示例)的相关文章

1.远程调用其他进程中的代码

学习记录. void usegoods() { _asm { push 3//3是小金疮药.金疮药id push 1 push 0 mov eax,0x79D330 call eax } } 上诉代码是通过od找出的一个call.然后用c++内嵌汇编来调用这个call void CrxjhcDlg::OnBnClickedButton1() { HWND h; h=::FindWindow(NULL,L"YB_OnlineClient");//获取游戏窗口句柄spy++ DWORD i

SQL注入原理与解决方法代码示例

一.什么是sql注入? 1.什么是sql注入呢? 所谓SQL注入,就是通过把SQL命令插入到Web表单递交或输入域名或页面请求的查询字符串,最终达到欺骗服务器执行恶意的SQL命令,比如先前的很多影视网站泄露VIP会员密码大多就是通过WEB表单递交查询字符暴出的,这类表单特别容易受到SQL注入式攻击.当应用程序使用输入内容来构造动态sql语句以访问数据库时,会发生sql注入攻击.如果代码使用存储过程,而这些存储过程作为包含未筛选的用户输入的字符串来传递,也会发生sql注入. 黑客通过SQL注入攻击

Dubbo搭建HelloWorld-搭建服务提供者与服务消费者并完成远程调用(附代码下载)

场景 Dubbo简介与基本概念: https://blog.csdn.net/BADAO_LIUMANG_QIZHI/article/details/103555224 Dubbo环境搭建-ZooKeeper注册中心: https://blog.csdn.net/BADAO_LIUMANG_QIZHI/article/details/103555470 Dubbo环境搭建-管理控制台dubbo-admin实现服务监控: https://blog.csdn.net/BADAO_LIUMANG_QI

AXIS2远程调用WebService示例(Eclipse+AXIS)

转自:http://www.cnblogs.com/lanxuezaipiao/archive/2013/05/10/3071584.html 我们将Web Service发布在Tomcat或者其他应用服务器上后,有两种方法可以调用该Web Service: 1.通过浏览器调用,返回规范的XML文件      2.通过客户端程序调用,返回结果可自定义格式 接下来,我利用Eclipse J2EE作为开发工具,演示一个Axis调用WebService的简单示例      第一种调用见我的另一篇博文:

alibaba远程调用框架dubbo原理

alibaba有好几个分布式框架,主要有:进行远程调用(类似于RMI的这种远程调用)的(dubbo.hsf),jms消息服务(napoli.notify),KV数据库(tair)等.这个框架/工具/产品在实现的时候,都考虑到了容灾,扩展,负载均衡,于是出现一个配置中心(ConfigServer)的东西来解决这些问题. 基本原理如图: 在我们的系统中,经常会有一些跨系统的调用,如在A系统中要调用B系统的一个服务,我们可能会使用RMI直接来进行,B系统发布一个RMI接口服务,然后A 系统就来通过RM

dubbo_远程同步调用原理

Dubbo缺省协议采用单一长连接和NIO异步通讯,适合于小数据量大并发的服务调用,以及服务消费者机器数远大于服务提供者机器数的情况. Dubbo缺省协议,使用基于mina1.1.7+hessian3.2.1的tbremoting交互. 连接个数:单连接 连接方式:长连接 传输协议:TCP 传输方式:NIO异步传输 序列化:Hessian二进制序列化 适用范围:传入传出参数数据包较小(建议小于100K),消费者比提供者个数多,单一消费者无法压满提供者,尽量不要用dubbo协议传输大文件或超大字符串

一个简单的AXIS远程调用Web Service示例

我们通常都将编写好的Web Service发布在Tomcat或者其他应用服务器上,然后通过浏览器调用该Web Service,返回规范的XML文件.但是如果我们不通过浏览器调用,而是通过客户端程序调用,该如何实现?      接下来,我们利用Eclipse作为开发工具,演示一个Axis调用WebService的简单示例.步骤如下:           第一步:新建Web Project (一定要是web project,不能是java project).      第二步:导入AXIS类库.(官

验证码识别与生成类API调用的代码示例合集:六位图片验证码生成、四位图片验证码生成、简单验证码识别等

以下示例代码适用于 www.apishop.net 网站下的API,使用本文提及的接口调用代码示例前,您需要先申请相应的API服务. 六位图片验证码生成:包括纯数字.小写字母.大写字母.大小写混合.数字+小写.数字+大写.数字+大小写等情况. 四位图片验证码生成:包括纯数字.小写字母.大写字母.大小写混合.数字+小写.数字+大写.数字+大小写等情况. 简单验证码识别:验证码类型 : 数字+字母, 纯英文, 纯数字,计算题 英数_验证码识别:纯数字,纯英文,数字+英文 中英数_验证码识别:英文.数

影视娱乐类API调用的代码示例合集:NBA赛事、电视节目等

以下示例代码适用于 www.apishop.net 网站下的API,使用本文提及的接口调用代码示例前,您需要先申请相应的API服务. NBA赛事:NBA篮球赛事赛程相关信息 电视节目:央视及各地卫视的电视节目时间表,包括本周及下周的电视节目内容 **API Shop(apishop.net)提供多达50款的常用第三方API,可以从github上下载代码示例合集:https://github.com/apishop/All-APIs** 以上接口均包含PHP.Python.C#和Java等四种语言