.NET Remoting 全面教程

目录

  1. 什么是 .NET Remoting?
  2. 核心概念
  3. 为什么现在不推荐使用 .NET Remoting?
  4. 简单示例:创建一个 "Hello World" Remoting 应用
    • 步骤 1: 定义远程对象 (Marshal-By-Value 对象)
    • 步骤 2: 创建服务器端
    • 步骤 3: 创建客户端
    • 步骤 4: 运行和测试
  5. 进阶概念
    • Marshal-By-Reference (MBR) 对象
    • 生命周期管理
    • 自定义信道
  6. 与 WCF 和 gRPC 的对比
  7. 总结与学习资源

什么是 .NET Remoting?

.NET Remoting 是微软在 .NET Framework 早期(.NET 1.0/1.1/2.0/3.0/3.5)推出的一种跨应用程序域的通信技术,它的主要目标是允许不同进程(甚至在同一台机器的不同计算机上)的应用程序像调用本地对象一样相互调用方法。

.net remoting教程
(图片来源网络,侵删)

你可以把它想象成一个“超级 DCOM”,它提供了比 DCOM 更灵活、更强大的功能,并且完全基于 .NET 的类型系统。

核心概念

要理解 .NET Remoting,必须掌握以下几个核心组件:

a. 远程对象

这是客户端想要调用的对象,它必须继承自 MarshalByRefObject 类,或者可以被序列化(实现 ISerializable 或标记为 [Serializable])。

  • Marshal-By-Reference (MBR): 对象本身不离开服务器,当客户端调用其方法时,实际上是调用一个代理对象上的方法,这个代理通过网络将请求发送到服务器上的真实对象,这就像一个遥控器,你按按钮,但真正的电视在另一个房间里。
  • Marshal-By-Value (MBV): 对象被完整地序列化(转换成字节流),然后从服务器发送到客户端,客户端得到的是这个对象的副本,之后的所有调用都在本地副本上进行,不再与服务器交互,这就像把一本书从图书馆借回家,你可以在家里阅读,不需要每次都跑回图书馆。

b. 信道

信道是远程对象传输数据的通道,它负责将方法调用序列化并通过网络发送,同时也将返回结果反序列化。

.net remoting教程
(图片来源网络,侵删)
  • .NET Remoting 提供了两种内置信道:
    • TcpChannel: 使用 TCP 协议,性能更高,更适合局域网或对性能要求高的场景。
    • HttpChannel: 使用 HTTP 协议,可以穿透防火墙,更适合互联网场景。
  • 信道可以配置使用不同的格式化程序 来序列化消息,BinaryFormatter(性能高)或 SoapFormatter(基于 XML,可读性好,但性能较低)。

c. 激活

激活是指客户端获取远程对象代理的过程。.NET Remoting 提供了两种激活方式:

  • 服务器端激活: 也称为“WellKnown”激活,服务器预先注册好一个类型,客户端通过一个众所周知的 URI(统一资源标识符)来请求该类型的实例,服务器会为每个客户端请求创建一个新的实例。
    • SingleCall: 每次客户端调用都会创建一个新的对象实例,调用结束后立即销毁,无状态。
    • Singleton: 整个应用程序域中只有一个对象实例,所有客户端共享这个实例,有状态。
  • 客户端激活: 客户端通过 new 关键字或 Activator.CreateInstance 来创建远程对象,服务器会为每个客户端创建一个专有的对象实例,并管理其生命周期。

d. 应用程序域

.NET Remoting 的一个强大之处在于它可以在同一个进程内创建多个应用程序域,每个 AppDomain 都像一个轻量级的进程,拥有独立的内存空间和加载的程序集。.NET Remoting 允许这些 AppDomain 之间像跨进程通信一样互相调用对象,而无需操作系统级别的进程间通信开销。

为什么现在不推荐使用 .NET Remoting?

这是一个非常重要的问题。.NET Remoting 是一项过时的技术。

  • 安全性问题: BinaryFormatter 存在严重的安全漏洞,容易被利用进行远程代码执行攻击,微软官方已不再推荐使用它。
  • 复杂性: 配置和使用相对复杂,容易出错。
  • 平台限制: 它是 .NET Framework 的专有技术,无法在 .NET Core 或 .NET 5+ 上运行,而现代的 .NET 是跨平台的。
  • 有更好的替代品:
    • WCF (Windows Communication Foundation): .NET Framework 的后继者,功能更强大、更安全、更灵活,支持多种协议和绑定。
    • ASP.NET Web API: 专注于构建 RESTful 服务,简单易用,是构建 HTTP 服务的首选。
    • gRPC: 现代高性能的 RPC 框架,基于 HTTP/2 和 Protocol Buffers,适合微服务架构。

除非你正在维护一个非常古老的 .NET Framework 应用程序,否则绝对不要在新项目中使用 .NET Remoting,本教程仅用于学习和理解历史技术。

.net remoting教程
(图片来源网络,侵删)

简单示例:创建一个 "Hello World" Remoting 应用

我们将创建一个简单的控制台应用程序,包含三个项目:

  1. SharedLibrary: 包含共享的远程对象接口和实现。
  2. Server: 服务器端,发布远程对象。
  3. Client: 客户端,调用远程对象的方法。

步骤 1: 定义远程对象 (Marshal-By-Value 对象)

这是一个最简单的例子,我们使用 MBV 对象。

  1. 创建一个新的类库项目 SharedLibrary

  2. 添加一个接口 IGreetingService.cs

    // SharedLibrary/IGreetingService.cs
    using System;
    namespace SharedLibrary
    {
        // 必须标记为 [Serializable] 才能被 MBV 传递
        [Serializable]
        public interface IGreetingService
        {
            string Greet(string name);
        }
    }
  3. 添加一个实现类 GreetingService.cs

    // SharedLibrary/GreetingService.cs
    namespace SharedLibrary
    {
        // 实现接口
        public class GreetingService : IGreetingService
        {
            public string Greet(string name)
            {
                Console.WriteLine($"[服务器端] 正在为 '{name}' 生成问候语...");
                return $"你好, {name}! 欢迎使用 .NET Remoting!";
            }
        }
    }
  4. SharedLibrary 的输出路径设置为与 ServerClient 相同,以便复制 DLL 文件,或者在生成后手动复制。

步骤 2: 创建服务器端

  1. 创建一个新的控制台应用程序项目 Server

  2. 添加对 SharedLibrary 项目的引用。

  3. 编写 Program.cs

    // Server/Program.cs
    using System;
    using System.Runtime.Remoting;
    using System.Runtime.Remoting.Channels;
    using System.Runtime.Remoting.Channels.Tcp;
    using SharedLibrary;
    namespace Server
    {
        class Program
        {
            static void Main(string[] args)
            {
                Console.WriteLine("服务器启动中...");
                // 1. 创建并注册 TCP 信道
                // 参数:端口号 和 格式化程序提供者
                TcpChannel channel = new TcpChannel(8080);
                ChannelServices.RegisterChannel(channel, false);
                // 2. 注册远程对象
                // 参数:对象在客户端访问的 URI ("remote") 和 对象类型
                RemotingConfiguration.RegisterWellKnownServiceType(
                    typeof(GreetingService),
                    "remote",
                    WellKnownObjectMode.Singleton); // 使用 Singleton 模式
                Console.WriteLine("服务器已启动,等待客户端连接...");
                Console.WriteLine("按任意键退出...");
                Console.ReadKey();
            }
        }
    }

步骤 3: 创建客户端

  1. 创建一个新的控制台应用程序项目 Client

  2. 添加对 SharedLibrary 项目的引用。

  3. 编写 Program.cs

    // Client/Program.cs
    using System;
    using System.Runtime.Remoting;
    using System.Runtime.Remoting.Channels;
    using System.Runtime.Remoting.Channels.Tcp;
    using SharedLibrary;
    namespace Client
    {
        class Program
        {
            static void Main(string[] args)
            {
                Console.WriteLine("客户端启动中...");
                // 1. 创建并注册 TCP 信道
                // 客户端只需要提供格式化程序提供者
                TcpChannel channel = new TcpChannel();
                ChannelServices.RegisterChannel(channel, false);
                // 2. 激活远程对象
                // 参数:服务器地址 ("tcp://localhost:8080/remote") 和 对象类型
                IGreetingService service = (IGreetingService)Activator.GetObject(
                    typeof(IGreetingService),
                    "tcp://localhost:8080/remote");
                // 3. 调用远程方法
                if (service != null)
                {
                    string greeting = service.Greet("张三");
                    Console.WriteLine($"[客户端] 收到来自服务器的问候: {greeting}");
                }
                else
                {
                    Console.WriteLine("无法连接到远程对象。");
                }
                Console.WriteLine("按任意键退出...");
                Console.ReadKey();
            }
        }
    }

步骤 4: 运行和测试

  1. 先启动服务器:运行 Server 项目,控制台会显示“服务器已启动...”。
  2. 再启动客户端:运行 Client 项目。
  3. 观察输出
    • 服务器控制台 会显示:[服务器端] 正在为 '张三' 生成问候语...
    • 客户端控制台 会显示:[客户端] 收到来自服务器的问候: 你好, 张三! 欢迎使用 .NET Remoting!

这证明了客户端成功调用了服务器上的方法。


进阶概念

a. Marshal-By-Reference (MBR) 对象

对于 MBR 对象,服务器端的代码需要稍作修改,并且客户端的调用方式也不同。

服务器端修改 (Server 项目):

// SharedLibrary/MBRGreetingService.cs
using System; // 必须添加这个 using
namespace SharedLibrary
{
    // 必须继承 MarshalByRefObject
    public class MBRGreetingService : MarshalByRefObject
    {
        public MBRGreetingService()
        {
            Console.WriteLine("[服务器] MBR 对象被构造!");
        }
        public string Greet(string name)
        {
            // 每次调用都会打印,证明是同一个对象(Singleton)
            Console.WriteLine($"[服务器端] MBR 对象正在为 '{name}' 生成问候语...");
            return $"你好, {name}! (来自 MBR 对象)";
        }
    }
}
// Server/Program.cs (修改部分)
// ... 其他代码不变
// 注册 MBR 对象
RemotingConfiguration.RegisterWellKnownServiceType(
    typeof(MBRGreetingService),
    "mbr_remote",
    WellKnownObjectMode.Singleton); // 仍然使用 Singleton

客户端修改 (Client 项目):

// Client/Program.cs (修改部分)
// ... 其他代码不变
// 激活 MBR 对象
// 注意:这里也是 Activator.GetObject
MBRGreetingService mbrService = (MBRGreetingService)Activator.GetObject(
    typeof(MBRGreetingService),
    "tcp://localhost:8080/mbr_remote");
if (mbrService != null)
{
    // 调用方法
    string greeting1 = mbrService.Greet("李四");
    Console.WriteLine($"[客户端] 第一次调用结果: {greeting1}");
    string greeting2 = mbrService.Greet("王五");
    Console.WriteLine($"[客户端] 第二次调用结果: {greeting2}");
}

当你运行这个 MBR 示例时,你会发现服务器端只打印了一次“MBR 对象被构造!”,但两次方法调用都打印了方法内的日志,这证明了客户端一直在使用同一个服务器端对象实例。

b. 生命周期管理

对于 MBR 对象,.NET Remoting 提供了 Lease-Based 生命周期管理,每个远程对象都有一个“租约”(Lease),租约到期后如果没有被续订,对象就会被垃圾回收。

  • 初始租约时间: 对象创建后存在的时间。
  • 租约管理器: 负责跟踪所有租约。
  • 续订: 客户端可以主动续订租约,保持对象活跃。

这个机制比较复杂,在实际应用中需要仔细配置。

c. 自定义信道

你可以实现自己的 IChannelReceiverIChannelSender 接口来创建自定义信道,例如通过命名管道、消息队列等进行通信,但这在 .NET Remoting 中非常罕见。


与 WCF 和 gRPC 的对比

特性 .NET Remoting WCF gRPC
时代 过时 较新,但已被标记为“维护中” 现代
平台 仅限 .NET Framework .NET Framework, .NET Core, .NET 5+ 跨平台
安全性 弱,BinaryFormatter 有漏洞 强,支持多种安全标准 强,基于 TLS
协议 TCP, HTTP HTTP, TCP, Named Pipes, MSMQ 等 HTTP/2, gRPC
数据格式 Binary, SOAP XML, JSON, Binary Protocol Buffers
主要用途 跨 AppDomain 通信 企业级服务(SOA) 微服务,高性能 RPC
配置 复杂,代码或配置文件 灵活,代码或配置文件 简单,基于 Protobuf 文件
推荐度 不推荐 维护中,新项目建议用 gRPC 或 Web API 推荐

总结与学习资源

.NET Remoting 是 .NET 生态系统中一个重要的历史里程碑,它首次提供了强大而灵活的分布式通信能力,由于其固有的安全风险、平台限制和复杂性,它已经被更现代、更安全、更通用的技术(如 WCF 和 gRPC)所取代。

学习资源:

  • 官方文档 (历史): Microsoft Docs - .NET Remoting (这些文档可能已不再更新)。
  • 书籍: 《.NET Framework 高级编程》(早期版本)中有详细的章节介绍。
  • 博客文章: 搜索 "dotnet remoting tutorial" 可以找到许多经典的英文教程,CodeProject 上的文章。

希望这份教程能帮助你全面地了解 .NET Remoting。