初探Remoting双向通信(二)

2013年06月25日 11:46:24
喜欢特别冷的冬天下着雪
阅读数 2977

                    版权声明:本文为博主原创文章,未经博主允许不得转载。                        https://blog.csdn.net/kkkkkxiaofei/article/details/9167829                    </div>
<link rel="stylesheet" href="https://csdnimg.cn/release/phoenix/template/css/ck_htmledit_views-cd6c485e8b.css">
<link rel="stylesheet" href="https://csdnimg.cn/release/phoenix/template/css/ck_htmledit_views-cd6c485e8b.css">
<div class="htmledit_views" id="content_views">

二、利用事件实现客户端向服务器通信
    接着上一篇,按照我的思路,远程对象中定义的事件在客户端触发,而在服务器端订阅,应该可以成功。现在放弃之前的示例代码,自己重新写一个版本,代码如下:

远程对象:


  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. namespace Remoting
  6. {
  7. public class RemotingObject:MarshalByRefObject
  8. {
  9. public delegate void MyDelegate(string msg);
  10. public static event MyDelegate myEvent;
  11. //触发事件
  12. public void TriggerEvent(string msg)
  13. {
  14. if (myEvent != null)
  15. myEvent(msg);
  16. }
  17. //无限生命周期
  18. public override object InitializeLifetimeService()
  19. {
  20. return null;
  21. }
  22. }
  23. }

服务器:


  1. using System;
  2. using System.Collections.Generic;
  3. using System.ComponentModel;
  4. using System.Data;
  5. using System.Drawing;
  6. using System.Linq;
  7. using System.Text;
  8. using System.Windows.Forms;
  9. using System.Runtime.Remoting;
  10. using System.Runtime.Remoting.Channels;
  11. using System.Runtime.Remoting.Channels.Tcp;
  12. using Remoting;
  13. namespace Server
  14. {
  15. public partial class ServerForm : Form
  16. {
  17. public ServerForm()
  18. {
  19. InitializeComponent();
  20. StartServer();
  21. }
  22. //开启服务器
  23. public void StartServer()
  24. {
  25. TcpChannel tcpchannel = new TcpChannel(8080);
  26. ChannelServices.RegisterChannel(tcpchannel,false);
  27. RemotingConfiguration.RegisterWellKnownServiceType(typeof(RemotingObject),"url",WellKnownObjectMode.Singleton);
  28. RemotingObject.myEvent += new RemotingObject.MyDelegate(RemotingObject_myEvent);
  29. }
  30. void RemotingObject_myEvent(string msg)
  31. {
  32. //跨线程调用
  33. textBox2.Invoke(new Action<string>(str => { textBox2.Text = str; }), msg);
  34. }
  35. }
  36. }

客户端:


  1. using System;
  2. using System.Collections.Generic;
  3. using System.ComponentModel;
  4. using System.Data;
  5. using System.Drawing;
  6. using System.Linq;
  7. using System.Text;
  8. using System.Windows.Forms;
  9. using System.Runtime.Remoting;
  10. using System.Runtime.Remoting.Channels;
  11. using System.Runtime.Remoting.Channels.Tcp;
  12. using Remoting;
  13. namespace Client
  14. {
  15. public partial class ClientForm : Form
  16. {
  17. RemotingObject obj;
  18. public ClientForm()
  19. {
  20. InitializeComponent();
  21. StartClient();
  22. }
  23. private void 发送_Click(object sender, EventArgs e)
  24. {
  25. obj.TriggerEvent("客户端--" + this.ClientIP() + System.Environment.NewLine + textBox1.Text + System.Environment.NewLine);
  26. }
  27. //开启客户端
  28. public void StartClient()
  29. {
  30. TcpChannel tcpchannel = new TcpChannel(0);
  31. ChannelServices.RegisterChannel(tcpchannel, false);
  32. obj = (RemotingObject)Activator.GetObject(typeof(RemotingObject), "tcp://localhost:8080/url");
  33. }
  34. //获取本地ip
  35. public string ClientIP()
  36. {
  37. return System.Net.Dns.GetHostAddresses(System.Net.Dns.GetHostName())[0].ToString();
  38. }
  39. }
  40. }

运行效果如下:

哈哈,如我所愿,利用事件确实实现了客户端与服务器的通信。

可是,这里面有一个小问题:在服务器订阅事件的时候我用到

RemotingObject.myEvent += new RemotingObject.MyDelegate(RemotingObject_myEvent);

这一句其实是我不得已而为之的,为什么这么说的。因为这里myEvent是静态的,只有这样我才可以用RemotingObject.myEvent订阅到事件。但是如果myEvent不是静态的呢?这时候如何去实例化一个对象,并且用"对象.myEvent"来订阅事件呢?如果我在服务器端自己new一个对象,那这个对象肯定和客户端激活得到的对象不是同一个引用。

(注:上面的Demo在此处下载http://download.csdn.net/detail/kkkkkxiaofei/5645629

带着这个疑问,我找了些资料。有了重大发现。

[SecuritySafeCritical]

    public static ObjRef Marshal(MarshalByRefObject Obj, string URI);

来看看官方的解释把:将给定的 System.MarshalByRefObject 转换为具有指定 URI 的 System.Runtime.Remoting.ObjRef 类的实例。

看到实例两个字我就激动了, 这里我的RemotingObject类就继承了System.MarshalByRefObject。这个ObjRef 类是做什么的?如果将其转换为ObjRef 类的实例又能怎么样呢?

再来看看ObjRef 吧。

ObjRef :存储生成代理以与远程对象通信所需要的所有信息。

有了上面的概念,我又有了点思路了:

之前客户端(RemotingObject)Activator.GetObject(typeof(RemotingObject), "tcp://localhost:8080/url")得到的这个对象,是服务器注册的RemotingConfiguration.RegisterWellKnownServiceType(typeof(RemotingObject),"url",WellKnownObjectMode.Singleton)这个对象的引用。在服务器端并不能获取这个对象。那如果我在服务器端显示创建一个对象,然后让客户端刚好能获取这个引用不就行了么。Marshal方法不就是显示生成服务器端的RemotingObject对象的代理么,客户端激活的代码已然不变,利用ip地址和url就能找到这个对象,这样2个程序域中的2个对象其实就是同一个引用。这么一来,就可以解决掉事件只能是静态的尴尬局面了,好了是时候验证我的想法了。代码如下,

远程对象:


  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. namespace Remoting
  6. {
  7. public class RemotingObject:MarshalByRefObject
  8. {
  9. public delegate void MyDelegate(string msg);
  10. public event MyDelegate myEvent;
  11. //触发事件
  12. public void TriggerEvent(string msg)
  13. {
  14. if (myEvent != null)
  15. myEvent(msg);
  16. }
  17. //无限生命周期
  18. public override object InitializeLifetimeService()
  19. {
  20. return null;
  21. }
  22. }
  23. }

客户端:


  1. using System;
  2. using System.Collections.Generic;
  3. using System.ComponentModel;
  4. using System.Data;
  5. using System.Drawing;
  6. using System.Linq;
  7. using System.Text;
  8. using System.Windows.Forms;
  9. using System.Runtime.Remoting;
  10. using System.Runtime.Remoting.Channels;
  11. using System.Runtime.Remoting.Channels.Tcp;
  12. using Remoting;
  13. namespace Client
  14. {
  15. public partial class ClientForm : Form
  16. {
  17. RemotingObject obj;
  18. public ClientForm()
  19. {
  20. InitializeComponent();
  21. StartClient();
  22. }
  23. private void 发送_Click(object sender, EventArgs e)
  24. {
  25. obj.TriggerEvent("客户端--" + this.ClientIP() + System.Environment.NewLine + textBox1.Text + System.Environment.NewLine);
  26. }
  27. //开启客户端
  28. public void StartClient()
  29. {
  30. TcpChannel tcpchannel = new TcpChannel(0);
  31. ChannelServices.RegisterChannel(tcpchannel, false);
  32. obj = (RemotingObject)Activator.GetObject(typeof(RemotingObject), "tcp://localhost:8080/url");
  33. }
  34. //获取本地ip
  35. public string ClientIP()
  36. {
  37. return System.Net.Dns.GetHostAddresses(System.Net.Dns.GetHostName())[0].ToString();
  38. }
  39. }
  40. }

服务器:


  1. using System;
  2. using System.Collections.Generic;
  3. using System.ComponentModel;
  4. using System.Data;
  5. using System.Drawing;
  6. using System.Linq;
  7. using System.Text;
  8. using System.Windows.Forms;
  9. using System.Runtime.Remoting;
  10. using System.Runtime.Remoting.Channels;
  11. using System.Runtime.Remoting.Channels.Tcp;
  12. using Remoting;
  13. namespace Server
  14. {
  15. public partial class ServerForm : Form
  16. {
  17. RemotingObject marshal_obj;
  18. public ServerForm()
  19. {
  20. InitializeComponent();
  21. StartServer();
  22. }
  23. //开启服务器
  24. public void StartServer()
  25. {
  26. TcpChannel tcpchannel = new TcpChannel(8080);
  27. ChannelServices.RegisterChannel(tcpchannel,false);
  28. //RemotingConfiguration.RegisterWellKnownServiceType(typeof(RemotingObject),"url",WellKnownObjectMode.Singleton);
  29. marshal_obj = new RemotingObject();
  30. ObjRef objRef = RemotingServices.Marshal(marshal_obj, "url");
  31. marshal_obj.myEvent += new RemotingObject.MyDelegate(RemotingObject_myEvent);
  32. }
  33. void RemotingObject_myEvent(string msg)
  34. {
  35. //跨线程调用
  36. textBox2.Invoke(new Action<string>(str => { textBox2.Text = str; }), msg);
  37. }
  38. }
  39. }

运行结果很乐观,如期所料

看来用Marshal方法确实可以让服务器和客户端都有一份远程对象的引用,咦,那这么说,服务器岂不是也可以主动触发事件,然后让客户端来绑定,这样就能实现服务器向客户端通信。哈哈,离我的项目需求又近了一步,不错不错,下篇试试实现这个问题。

(注:上面的Demo在此处下载http://download.csdn.net/detail/kkkkkxiaofei/5646103

初探Remoting双向通信(二)的更多相关文章

  1. 初探Remoting双向通信(四)

    原 初探Remoting双向通信(四) 2013年06月26日 11:11:32 喜欢特别冷的冬天下着雪 阅读数 2632 版权声明:本文为博主原创文章,未经博主允许不得转载. https://blo ...

  2. 初探Remoting双向通信(三)

    原 初探Remoting双向通信(三) 2013年06月25日 17:51:08 喜欢特别冷的冬天下着雪 阅读数 4741 版权声明:本文为博主原创文章,未经博主允许不得转载. https://blo ...

  3. 初探remoting双向通信(一)

    原 初探remoting双向通信(一) 2013年06月24日 15:47:07 喜欢特别冷的冬天下着雪 阅读数 4389 版权声明:本文为博主原创文章,未经博主允许不得转载. https://blo ...

  4. 初探JavaScript(二)——JS如何动态操控HTML

    除去五一三天,我已经和<JavaScript Dom编程艺术>磨合了六天,第一印象很好.慢慢的,我发现这是一块排骨,除了肉还有骨头.遇到不解的地方就会多看几遍,实在不懂的先跳过,毕竟,初次 ...

  5. C# 实现Remoting双向通信

    本篇文章主要介绍了C# 实现Remoting双向通信,.Net Remoting 是由客户端通过Remoting,访问通道以获得服务端对象,再通过代理解析为客户端对象来实现通信的 闲来无事想玩玩双向通 ...

  6. C# Remoting双向通信

    闲来无事想玩玩双向通信,实现类似QQ的互发消息的功能.于是乎开始学习.Net Remoting. .Net Remoting 是由客户端通过Remoting,访问通道以获得服务端对象,再通过代理解析为 ...

  7. MongoDB初探系列之二:认识MongoDB提供的一些经常使用工具

    在初探一中,我们已经能够顺利的将MongoDB在我们自己的机器上跑起来了. 可是在其bin文件夹以下另一些我们不熟知的工具.接下来,将介绍一下各个小工具的用途以及初探一中MongoDB在data文件夹 ...

  8. javascript --- 原型初探七日谈(二)

    扩展内建对象: 在javascript中,内建对象的构造函数都是可以通过其原型来进行扩展的.这意味着我们可以做一些事情,例如我们要往数组原型中添加一个新方法,就可以在其所有的数组中使用,下面我们来试试 ...

  9. 跟我一起学WCF(2)——利用.NET Remoting技术开发分布式应用

    一.引言 上一篇博文分享了消息队列(MSMQ)技术来实现分布式应用,在这篇博文继续分享下.NET平台下另一种分布式技术——.NET Remoting. 二..NET Remoting 介绍 2.1 . ...

随机推荐

  1. Linux.中断处理.入口x86平台entry_32.S

    Linux.中断处理.入口x86平台entry_32.S Linux.中断处理.入口x86平台entry_32.S 在保护模式下处理器是通过中断号和IDTR找到中断处理程序的入口地址的.IDTR存的是 ...

  2. 【转】在配置静态IP的时候遇到 :bringing up interface eth0 : error unknown connection

    首先这是动态ip配置成功的结果 接下来切换到root用户来配置静态的 按照静态ip的配置方法配置好文件后(具体过程这里就不多加说明) 然后保存退出 当我们重启网卡的时候问题来了(因为本人有点强迫症,多 ...

  3. go读写文本文件

    一.文件读取 1. 将整个文件读取到内存中 package main import ( "flag" "fmt" "io/ioutil" ) ...

  4. js自增++与自减--运算符

    /** * 自增(++)与自减(--)运算符 */ // 自增示例 var a = 1, c, d, e; console.log(`a++ = ${a++}`); // a++ = 1 consol ...

  5. JS中常见的兼容

    1.阻止事件冒泡 e.stopPropagation()   ||    e.cancelBubble function stopBubble(e){ if (e.cancelBubble) { e. ...

  6. 2018-12-25-win2d-图片水印

    title author date CreateTime categories win2d 图片水印 lindexi 2018-12-25 10:37:52 +0800 2018-03-19 08:3 ...

  7. 2019HDU多校训练第二场 Longest Subarray

    题意:给你一个串,问满足以下条件的子串中最长的是多长:对于每个数字,要么在这个子串没出现过,要么出现次数超过k次. 思路:对于这类问题,常常转化为数据结构的询问问题.我们考虑枚举右端点,对于当前右端点 ...

  8. 虚拟机设置静态IP地址

    前言 NAT连接方式只能配置一次,配置好子网掩码和网关IP后,虚拟机NAT连接的ip段都是同一个ip段 1.菜单栏选择 编辑 -> 虚拟网络编辑器,打开虚拟网络编辑器对话框,选择Vmnet8 N ...

  9. 对struct typedef *的认识

    typedef struct node { ……… }NODE,*PNODE; 应该等价于 typedef struct node NODE;//struct node = NODE,eg:struc ...

  10. 21.Semaphore信号量

    Semaphore是一种基于计数的信号量.它可以设定一个阈值,基于此,多个线程竞争获取许可信号,做自己的申请后归还,超过阈值后,线程申请许可信号将会被阻塞.Semaphore可以用来构建一些对象池,资 ...