博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
初探remoting双向通信(一)
阅读量:4973 次
发布时间:2019-06-12

本文共 4860 字,大约阅读时间需要 16 分钟。

初探remoting双向通信(一)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/kkkkkxiaofei/article/details/9162911

 

   我始终认为,在项目中边学边用才能将某项技术真正掌握,才能真正理解。最近做了个项目,简单介绍下:主要用Winform,内嵌有百度和谷歌2种类型的地图,此为服务器端。客户端是由另外一家公司做的一个板子,通俗点说就是GSM+GPS,可以利用TCP实时的给地图上传各种信息。客户端是安装的每辆行驶在高速公路的车辆上的,以此实现对高速公路安全的预警和监控。现在项目第一版已经差不多了,要去给客户安装软件。可问题来了,值班室可能有5-8个人要使用软件,而且其中一个还要安装在大屏幕上。呢就必须让这几个软件同步执行,当一个车辆上传坐标时,应该同时出现在8个机子上才对,当有一个机子的值班人员需要在地图上标记一个预警信息时,其他7个机子也应该同步更新信息才对。为此,我就开始了我的Remoting学习之路。

一、从一个小例子开始

    我想这种方式是现今大多数程序员最喜欢的方式了。“只要有DEMO,就别跟我说技术,是不?”哈哈,都是百度程序员。好了我就用百度程序员的方式开始,下面用某位仁兄的例子开始,这也是我网上搜的:

1.0定义对象

 
namespace RemoteSample
{
public class RemoteObject : System.MarshalByRefObject
{
public RemoteObject()
{
System.Console.WriteLine("我被构造了!");
}
public int sum(int a, int b)
{
return a + b;
}
}
}

 

将其编译为一个lib文件:csc /t:library RemoteObjec.cs

2.0服务器端

 
using System;
using System.Runtime;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Channels.Tcp;
using RemoteSample;
namespace RemoteSampleServer
{
public class RemoteServer
{
public static void Main(String[] args)
{
TcpServerChannel channel =new TcpServerChannel(6666);
ChannelServices.RegisterChannel(channel);
RemotingConfiguration.RegisterWellKnownServiceType(typeof(RemoteObject),
"RemoteObject", WellKnownObjectMode.SingleCall);
System.Console.WriteLine("Press Any Key");
System.Console.ReadLine();
}
}
}

将其编译为一个exe文件:csc /r:System.Runtime.Remoting.dll /r:RemoteObject.dll RemoteServer.cs

3.0客户端

 

 
using System;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Channels.Tcp;
using RemoteSample;
namespace RemoteSampleClient
{
public class RemoteClient
{
public static void Main(string[] args)
{
ChannelServices.RegisterChannel(new TcpClientChannel());
RemoteObject remoteobj = (RemoteObject)Activator.GetObject(typeof(RemoteObject),
"tcp://localhost:6666/RemoteObject");
Console.WriteLine("1 + 2 = "+ remoteobj.sum(1,2).ToString());
Console.ReadLine();
}
}
}

 

同样的,将其编译为exe文件:csc /r:System.Runtime.Remoting.dll /r:RemoteObject.dll RemoteClient.cs

然后先运行RemoteServer.exe,再运行RemoteClient.exe

 

输出:

我被构造了!(server端)

3(client端)

    假如你身边有2台电脑,再试试把其中的"tcp://localhost:6666/RemoteObject"改为一个具体的IP地址,如"tcp://59.74.137.215:6666/RemoteObject";之后将RemoteServer.exeRemoteObject.dll拷贝后,在一台电脑上运行。再将RemoteClient.exeRemoteObject.dll拷贝后再另一台电脑里运行。运行的结果和上面一样。这时我就有疑问了:

1.客户端获得的remoteobj,到底是怎么来的。

2.remoteobj调用的方法是谁的?服务器还是客户端?

3.这么做有什么意义?

    先从第1个开始着手。我很好奇这个dll起的作用。为什么客户端和服务器都需要一份dll?从上面的运行结果来看,server端既然能执行构造函数,那说明对象一定是再server端创建的,只是说客户端用某种方式获取了这个对象的引用。这样的话我就推测问题2一定是调用的服务器端的方法。那么,客户端的dll到底有什么用呢?如果不放这个dll我想连语法都通过不了把,RemoteObject remoteobj = (RemoteObject)Activator.GetObject(typeof(RemoteObject), "tcp://localhost:6666/RemoteObject");这行里的RemoteObject肯定就需要dll来声明。嘿嘿,我就猜想,它绝对只是声明的作用,为了验证我对1,2问题的猜想。其中运行server端那台的机子代码不变,客户端的机子中代码稍稍改变下,将RemotingObject重新按以下代码编译。

 

 
namespace RemoteSample
{
public class RemoteObject : System.MarshalByRefObject
{
public RemoteObject()
{
System.Console.WriteLine("我被构造了!");
}
public int sum(int a, int b)
{
return 0//返回0
}
}
}

 

然后替换掉客户端机子上的那个dll,注意此时客户端和服务器端的dll不一样奥。也许你已经看出了猫腻,哈哈,运行下把。

输出:

我被构造了!(server端)

3(client端)

    我了个去,坑爹了把。这东西确实是调用的服务器端的方法,虽然在客户端运行着,但是跟客户端没半毛钱关系。前两个问题算是勉强解决了,再说解决第三个问题的时候,我是时候该看下到底什么是remoting的,这个共享的对象又是怎么获取的。我虽然很喜欢搜百度,但遇到技术问题很少去看百度百科,说一大堆废话。不过关于remoting的介绍,这个百科说的还真不错,后来我发现这个百度百科也是抄的(谁先谁后不知道奥),在博客园里找到了"虾皮",貌似这是原创(以下摘自百科)。

    Microsoft .NET Remoting 提供了一种允许对象通过应用程序域与另一对象进行交互的框架。这也正是我们使用Remoting的原因。为什么呢?在Windows操作系统中,是将应用程序分离为单独的进程。这个进程形成了应用程序代码和数据周围的一道边界。如果不采用进程间通信(RPC)机制,则在一个进程中执行的代码就不能访问另一进程。这是一种操作系统对应用程序的保护机制。然而在某些情况下,我们需要跨过应用程序域,与另外的应用程序域进行通信,即穿越边界。

    在Remoting中是通过通道(channel)来实现两个应用程序域之间对象的通信的。首先,客户端通过Remoting,访问通道以获得服务端对象,再通过代理解析为客户端对象。这就提供一种可能性,即以服务的方式来发布服务器对象。远程对象代码可以运行在服务器上(如服务器激活的对象和客户端激活的对象),然后客户端再通过Remoting连接服务器,获得该服务对象并通过序列化在客户端运行。
    在Remoting中,对于要传递的对象,设计者除了需要了解通道的类型和端口号之外,无需再了解数据包的格式。但必须注意的是,客户端在获取服务器端对象时,并不是获得实际的服务端对象,而是获得它的引用。这既保证了客户端和服务器端有关对象的松散耦合,同时也优化了通信的性能。
 
    通读上面的定义,我想很牛逼哄哄的几个词会停留在你的脑海,交互式框架、进程间通信、跨过程序域、信道、代理等等。。。。为了了解这些,确实有必要知道些细节定义。
    我自己的总结如下:
远程对象:这个对象就是上面封装的那个dll。远程对象就是运行在服务器上的对象,客户端不能获取这个对象,只能获取这个对象的引用(序列化)或者代理。这个对象必须继承自MarshalByRefObject(允许支持在远程处理的应用程序中跨应用程序域边界访问对象).
信道:主要的有TCP,HTTP。(补加一句:一个应用程序在关闭时,一定要注销已注册的信道。否则会报错“Remoting对象已经断开连接或不在服务器上”)
激活方式:激活方式主要分客户端激活和服务器激活,我没用那么多,我只研究了服务器端激活,即SingleCall和SingleTon方式。SingleCall方式是客户端每次实例化一个对象,比如上面的代码,可以在启动一个server的时候启动多个client,此时每次启动都会有“我被构造了”。而SingleTon方式则可以简单的理解为单例模式,所有客户端获得都是同一个对象的引用,上面的代码如果改为SingleTon,则“我被构造了”只会出现一次。
    总结起来就是,服务器先注册信道,再注册对象,之后客户端再注册信道,而后获取对象。

    看了这么多的资料,也了解了些remoting,是时候说第3个问题了。还是想不通这又有什么意义呢?服务器中有某个方法可供客户端调用,那我还不如两边都using一下这个dll,还搞什么remoting这么麻烦的干嘛啊。初看起来确实是这样的。但是仔细想想,问题出在上面的代码太过于简单了。因为上面的代码调用的方法都是写死的,对象就在服务器停留了一小会调用了一下方法就走了,和服务器其实没有太大的联系。可是别忘了,.net有委托,有事件啊。如果注册的对象里面是有事件的,那么我在客户端触发该事件,而服务器订阅该事件,那岂不是作用大了去了。这似乎和我的项目需求沾边了,很高兴。。。继续研究ing,下篇继续。

 

 

 

 

 

 

 

转载于:https://www.cnblogs.com/owenzh/p/11175455.html

你可能感兴趣的文章
推荐阅读
查看>>
微信支付
查看>>
fatal error LNK1123: 转换到 COFF 期间失败: 文件无效或损坏
查看>>
XCTF-upload
查看>>
三步学会解决VS生成配置问题
查看>>
AtCoder Beginner Contest 121 题解
查看>>
Redis热点问题发现及通用解决方案
查看>>
Android之网络开发详解
查看>>
*Bash:如何用bash 转义 URL里的特殊字符,让其在sed不会产生歧义?
查看>>
IT笔面试题
查看>>
[CTSC2012]熟悉的文章 后缀自动机
查看>>
纯手工打造[博客园-博文数据分析]及技术分享(java)
查看>>
POJ 1961 KMP
查看>>
移动web资源整理
查看>>
ODBC, OLEDB, ADO, ADO.Net的演化简史
查看>>
如何实现div的高度100%填充
查看>>
计算机的分类
查看>>
探索c#之一致性Hash详解
查看>>
android 到底是什么决定了app的名称 application label activity label
查看>>
40026118素数的个数
查看>>