zoukankan      html  css  js  c++  java
  • 初探Remoting双向通信(二)

    初探Remoting双向通信(二)

                        版权声明:本文为博主原创文章,未经博主允许不得转载。                        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


     

  • 相关阅读:
    deepin15.11安装Oracle JDK
    API文档-BASE-BASE
    miniui控件的el属性(自动生成的标签)
    miniui从继承看控件处理
    miniui中的继承
    miniui加载(二)
    miniui 加载文件时会做的一些事情
    二、运行盛派的Demo(看下效果)
    一、选择云服务器和测试微信公众号Token
    绘制圆角(2)
  • 原文地址:https://www.cnblogs.com/owenzh/p/11175457.html
Copyright © 2011-2022 走看看