最近做一个项目,需要用到Remoting的远程事件处理。我写了一个例子,在本机运行没问题,可是当我把服务器端拷到服务器上再运行的时候,就不行了。包括我下载的 张逸 老师的 Remoting事件(服务端广播) 示例放到服务器上也不可用。Remoting的事件处理在互联网不可应用吗?服务器端代码(Server):
using System;
using System.Collections.Generic;
using System.Text;
using ClassLib;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Channels.Tcp;namespace Server
{
    class Program
    {
        static void Main(string[] args)
        {
            BinaryServerFormatterSinkProvider serverProvider = new BinaryServerFormatterSinkProvider();
            BinaryClientFormatterSinkProvider clientProvider = new BinaryClientFormatterSinkProvider();
            serverProvider.TypeFilterLevel = System.Runtime.Serialization.Formatters.TypeFilterLevel.Full;            System.Collections.Hashtable props = new System.Collections.Hashtable();
            props["port"] = 8081;
            TcpChannel channel = new TcpChannel(props, clientProvider, serverProvider);
            ChannelServices.RegisterChannel(channel, false);            RemotingConfiguration.RegisterWellKnownServiceType(typeof(SayHello), "SayHello", WellKnownObjectMode.Singleton);
            RemotingConfiguration.CustomErrorsMode = CustomErrorsModes.Off;            Console.ReadKey();
        }
    }
}客户端代码(Client):
using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Channels.Tcp;
using ClassLib;namespace Client
{
    class Program
    {
        static void Main(string[] args)
        {
            TcpChannel channel = new TcpChannel();
            ChannelServices.RegisterChannel(channel, false);            RemotingConfiguration.RegisterWellKnownClientType(typeof(SayHello), "tcp://219.235.3.120:8081/SayHello");            BinaryServerFormatterSinkProvider serverProvider = new BinaryServerFormatterSinkProvider();
            BinaryClientFormatterSinkProvider clientProvider = new BinaryClientFormatterSinkProvider();
            serverProvider.TypeFilterLevel = System.Runtime.Serialization.Formatters.TypeFilterLevel.Full;            System.Collections.Hashtable props = new System.Collections.Hashtable();
            props["port"] = 8082;
            props["name"] = "tcp2";
            TcpChannel channel1 = new TcpChannel(props, clientProvider, serverProvider);
            ChannelServices.RegisterChannel(channel1, false);            RemotingConfiguration.RegisterWellKnownServiceType(typeof(Common.EventCenter), "EventCenter", WellKnownObjectMode.Singleton);
            RemotingConfiguration.CustomErrorsMode = CustomErrorsModes.Off;            SayHello Hello = new SayHello();
            Common.EventCenter center = new Common.EventCenter();
            center.AfterSaid += new Common.AfterSaidEventHandler(Hello_AfterSaid);
            Hello.AfterSaid += new Common.AfterSaidEventHandler(center.Method);
            Hello.Say();
            Console.ReadKey();
        }        static void Hello_AfterSaid(object sender, Common.AfterSaidEventArgs e)
        {
            Console.WriteLine("事件触发");
        }
    }
}
公共类库代码(Common):
using System;
using System.Collections.Generic;
using System.Text;namespace Common
{
    [Serializable]
    public class EventCenter : MarshalByRefObject
    {
        public event Common.AfterSaidEventHandler AfterSaid;        public void Method(object sender, AfterSaidEventArgs e)
        {
            if (AfterSaid != null)
                AfterSaid(this, new Common.AfterSaidEventArgs("Hello"));
        }
    }    /// <summary>
    /// SayHello后的事件委托
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    [Serializable]
    public delegate void AfterSaidEventHandler(object sender, AfterSaidEventArgs e);    /// <summary>
    /// SayHello后触发事件的参数类
    /// </summary>
    [Serializable]
    public class AfterSaidEventArgs : EventArgs
    {
        /// <summary>
        /// 刚刚说过的话
        /// </summary>
        public string StrSaid;        public AfterSaidEventArgs(string str)
        {
            StrSaid = str;
        }
    }
}事件类代码(ClassLib):
using System;
using System.Collections.Generic;
using System.Text;namespace ClassLib
{
    /// <summary>
    /// 一个会说Hello的类
    /// </summary>
    public class SayHello : MarshalByRefObject
    {
        private static event Common.AfterSaidEventHandler _AfterSaid;        public SayHello()
        { }        /// <summary>
        /// 说完Hello后触发的事件
        /// </summary>
        public event Common.AfterSaidEventHandler AfterSaid
        {
            add
            {
                _AfterSaid += value;
            }
            remove
            {
                _AfterSaid -= value;
            }
        }        /// <summary>
        /// 说一句 Hello
        /// </summary>
        public void Say()
        {
            Console.WriteLine("Hello");
            if (_AfterSaid != null)
                _AfterSaid(this, new Common.AfterSaidEventArgs("Hello"));
        }
    }
}

解决方案 »

  1.   

    关注!!!
    一直学习Remoting,还没做过例子呢!!
    up!!
      

  2.   

    Remoting比较适合局域网环境,但因特网肯定也可以
      

  3.   

    如果服务器可以主动连接客户端就可用,反之不能。因为Remoting的Socket连接是短连接。
      

  4.   

    Remoting主要是面向同构网络环境,即网络主机平台类似场合,其采用的是二进制数据串行化标准,所以多应用于intranet,数据传输效率高。但是一般在异构广域网场合还是多采用SOAP+Web   Service,因为主机环境多是异构的,Web   Service串行化标准采用SOAP方式是可以跨平台解释的,而且Web   Service本身就考虑了穿越防火墙的问题。
      

  5.   

     .NET   Remoting有两种信道:使用HTTP和TCP信道之间的区别在于:如果应用程序是在局域网上运行,则最好使用TCP信道,因为它的性能要好于HTTP信道;如果应用程序是在互联网上运行,则有时候根据防火墙的配置,HTTP是唯一的选择。需要记住的是,如果使用了防火墙软件,则防火墙应该配置成允许TCP数据流量通过你为对象选择的端口。     
      

  6.   

    在google上搜索了一些零碎的资料,原因可能是::.NET Framework自带的TcpChannel和HttpChannel不支持跨越防火墙的Event Callback。这是因为.NET内部的协议通道只支持单向通信,Callback和原始方法调用需要两个独立通道。Remoting要为事件回调的Session建立一个独立的协议通道,但是因为防火墙的关系没法得到Client的确切IP地址,这个Channel也就建立不起来。 
    解决的方法是编写一个可以双向通信的TcpChannel 看来还是穿不了防火墙,呵呵。
    写一个双向通道看来是没有时间了,算了,暂时用P2P形式的函数代替事件吧。希望大家继续讨论,找到一个比较好的处理方法。
      

  7.   

    好像是不能穿越防火墙。所以remoting一般别用双向事件。不知道WCF怎么样
      

  8.   

    一般来说除非是客户端与服务器的开发都由自己做或控制,可以自己编写remoting的通讯协议,这样的通讯在互联网上放着是没有问题的,但是如果是你自己只能写客户端的程序然后采用remoting的方式去进行通讯可能有点不太好,可以考虑用webservice
      

  9.   

        props["port"] = 8081; 
                TcpChannel channel = new TcpChannel(props, clientProvider, serverProvider
    信道改成httpchannel 端口改成8080 然后两边防火墙先全部关闭调试ok就说明程序没有问题
      

  10.   

    貌似Remoting的事件处理默认使用TCP的,所以在局域网比较好
    而且事件是需要回调的,客户端有防火墙的话就不好办了不过自定义协议的话就另当别论不过这部分很深奥期待高人出现
      

  11.   

    用webservice的话就算了。因为用webservice根本不支持回调,效率也太低。
      

  12.   

    如果服务器可以主动连接客户端就可用,反之不能。 因为Remoting的Socket连接是短连接。
      

  13.   

    哦,忘了告诉大家解决的办法。在 "知秋一叶" 的Blog里有篇文章,里面详细描述了这个问题的原因,并提供了两个双向通道的可载址。我是使用了他提供的双向通道把这个问题解决的。地址:http://blog.joycode.com/qqchen/posts/399.aspx
      

  14.   

    对于Remoting,我一直很失望,失望到了要自己动手制作自己的远程调用框架……痛并快乐着
      

  15.   

    你可以试一试
    GenuineChannels和 BidirectionalTCPChannel他们都实现了TCP单通道双向通信.
    第一个收费
    第二个免费不过帮助文档全英文.
      

  16.   

    复happybebe 事实上,没有你想的这么简单的,呵呵。因为用单向通道的话,服务器根本无法获知客户端的IP,所以也就无法建立服务器到客户端的Callback连接。在本机测试的话,是不用考虑这个的。
      

  17.   

    remoting是个好东西,可搜索的资料有限,做起来也困难。