C# 封送和长途编程先容

[复制链接]
发表于 2025-11-3 07:48:15 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

×

.NET学习资料

.NET学习资料

.NET学习资料


在 C# 编程范畴中,封送(Marshaling)和长途编程(Remote Programming)是两个极为告急的概念,它们为开发者提供了与差别情况、差别进程或差别呆板上的代码举行交互的本事,极大地拓展了应用步调的功能和实用范围。
一、C# 封送

(一)界说与作用

封送是指在托管代码(如 C# 编写的代码,由公共语言运行时 CLR 管理)和非托管代码(如 C、C++ 编写的代码,没有 CLR 到场)之间举行数据转换和转达的过程。差别编程语言和情况在调用约定、布局约定、根本数据范例巨细、对象创建与烧毁约定以及筹划准则等方面存在差别。比方,C# 中的char范例和 C 中的char范例在巨细和编码方式上大概差别。因此,须要封送来办理这些差别,确保数据可以大概在差别情况之间正确转达和明白 。它就像是一座桥梁,毗连着托管天下和非托管天下,使得两者可以大概举行有用的通讯。
(二)常见的封送范例及处理处罚方式

blittable 范例

像byte、short、int、long等及其无符号对应范例,这些范例在托管和非托管代码之间转达时,不须要特殊的封送处理处罚,由于它们在差别情况中的内存布局和体现方式是划一的,可以直接举行数据传输。
非 blittable 范例

字符串范例:在 C# 与非托管代码交互时,若要将string封送到非托管函数,可以使用Marshal.StringToHGlobalAnsi、Marshal.StringToHGlobalAuto、Marshal.StringToHGlobalUni等方法 ,利用完成后需调用Marshal.FreeHGlobal开释内存;从非托管函数中取出string则可使用Marshal.PtrToStringAnsi、Marshal.PtrToStringAuto、Marshal.PtrToStringUni。比方,当调用一个非托管的 C 函数,该函数汲取一个 ANSI 编码的字符串参数时,就可以使用Marshal.StringToHGlobalAnsi将 C# 中的string转换为符合要求的非托管内存中的字符串情势。
数组范例:对于byte[](或其他底子范例的数组),可以使用Marshal.Copy方法实现从byte[]拷贝封送到非托管函数,或从非托管函数拷贝封送到byte[] 。别的,还可以接纳固定内存直接传送byte[]的原始地点的方式(这种方式省去了申请内存和拷贝的开销,速率更快),详细是使用GCHandle并指定GCHandleType.Pinned范例。假设须要将一个字节数组转达给非托管代码举行快速处理处罚,固定内存地点的方式就能进步数据传输服从。
委托范例:从delegate封送到非托管函数可使用Marshal.GetFunctionPointerForDelegate,从非托管函数中取出则使用Marshal.GetDelegateForFunctionPointer 。在封送到非托管函数时,要确保垃圾采取器(GC)不会采取委托,通常须要保持引用但不须要将其固定。比如在实现回调函数机制时,就大概涉及委托范例的封送。
布局体范例:在 C# 中按雷同次序和对应数据范例声明一个同样的struct(只能使用底子范例和固定长度的数组),而且标记StructLayout的LayoutKind.Sequential属性,然后使用Marshal.StructureToPtr和Marshal.PtrToStructure举行封送。当与非托管代码举行布局体数据交互时,这种方式能包管数据布局的正确转达。
(三)主动封送与手动封送

主动封送:当 C# 声明的extern函数返回范例和参数范例中有托管范例(如string、byte[]、委托等)时,CLR 会主动举行封送处理处罚,这大大节流了开发者编写封送代码的时间和精力。比方,在调用一个非托管的 DLL 函数,该函数的参数是一个字符串时,C# 代码中无需额外编写复杂的封送代码,CLR 会主动完成字符串范例的封送转换。
手动封送:在某些特殊情况下,主动封送无法满意需求,就须要手动举行封送。比如当string的编码是 UTF - 8 之类的非 ANSI 非 UTF - 16 编码时,必须手动举行封送并同时转换编码;又大概委托转换成函数指针的利用比力耗时,假如有频仍的对同一委托举行封送调用,预存转换后的效果可以大概显着提升性能,此时也须要手动举行封送处理处罚。
二、C# 长途编程

(一).NET Remoting 框架概述

.NET Remoting 是一种分布式处理处罚框架,它允许对象通过应用步调域与另一对象举行交互 ,可以看作是 DCOM 的一种升级,而且很好地融合到了.NET 平台下。其核心上风在于提供了一种机动且抽象的进程间通讯方式,使得开发者无需关注详细的客户端或服务器应用步调域,也无需关心特定的通讯协议,就能实现差别应用步调域乃至差别呆板上的对象之间的通讯。
(二)重要组件

可长途处理处罚的对象(Remoteable Object):这是须要在长途情况中被访问和调用的对象。它必须继续自MarshalByRefObject类,以便可以大概凌驾应用步调域举行通讯。比方,一个实现了业务逻辑的服务类,盼望被长途客户端调用其方法,就可以让这个类继续MarshalByRefObject。
长途监听应用步调(Remote Listener Application):负责监听对长途对象的哀求。它创建并注册通讯通道,同时注册长途对象,使其可以大概被长途客户端发现和访问。比如在服务器端,通过创建一个 TCP 或 HTTP 通道,并将长途对象注册到该通道上,等候客户端的毗连哀求。
长途客户端应用步调(Remote Client Application):向长途对象发出哀求。客户端通过 Remoting 框架,访问通道以获取服务器端对象的引用,然后通过该引用调用长途对象的方法。在客户端代码中,起首创建一个与服务器端对应的通道,然后使用Activator.GetObject等方法获取长途对象的引用,进而调用其公开的方法。
(三)通讯原理与通道

通讯原理:在 Remoting 中,客户端获取服务器端对象时,得到的并不是现实的服务端对象,而是它的引用,这包管了客户端和服务器端对象的疏松耦合,同时优化了通讯性能。客户端通过通道发送哀求消息,服务器端通过相应的通道汲取哀求并处理处罚,然后将效果通过通道返回给客户端 。整个过程就像是客户端和服务器端通过一条 “通讯管道” 举行交互,而这条 “管道” 就是通道。
通道范例:重要支持 TCP(传输控制协议)和 HTTP(超文本传输协议)通道。使用 TCP 通道时,数据以二进制情势传输,服从较高,恰当在内部网络情况中使用;而 HTTP 通道则基于 HTTP 协议,数据以 SOAP(简朴对象访问协议)格式传输,具有更好的跨平台和跨网络情况的兼容性,恰当在 Internet 等复杂网络情况中使用。
(四)代码示例

界说长途对象

  1. using System;
  2. namespace RemoteObject
  3. {
  4.     public class MyRemoteObject : MarshalByRefObject
  5.     {
  6.         public MyRemoteObject()
  7.         {
  8.         }
  9.         public int Add(int a, int b)
  10.         {
  11.             return a + b;
  12.         }
  13.     }
  14. }
复制代码
服务器端代码

  1. using System;
  2. using System.Runtime.Remoting.Channels;
  3. using System.Runtime.Remoting.Channels.Tcp;
  4. using RemoteObject;
  5. namespace RemoteServer
  6. {
  7.     class Program
  8.     {
  9.         static void Main(string[] args)
  10.         {
  11.             // 创建TCP服务器通道,端口号为8080
  12.             TcpServerChannel channel = new TcpServerChannel(8080);
  13.             // 注册通道
  14.             ChannelServices.RegisterChannel(channel, false);
  15.             // 注册远程对象,对象URI为"MyRemoteObject",激活模式为单例
  16.             RemotingConfiguration.RegisterWellKnownServiceType(typeof(MyRemoteObject), "MyRemoteObject", WellKnownObjectMode.Singleton);
  17.             Console.WriteLine("服务器已启动,等待客户端连接...");
  18.             Console.Read();
  19.         }
  20.     }
  21. }
复制代码
客户端代码

  1. using System;
  2. using System.Runtime.Remoting.Channels;
  3. using System.Runtime.Remoting.Channels.Tcp;
  4. using RemoteObject;
  5. namespace RemoteClient
  6. {
  7.     class Program
  8.     {
  9.         static void Main(string[] args)
  10.         {
  11.             // 创建TCP客户端通道
  12.             TcpClientChannel channel = new TcpClientChannel();
  13.             // 注册通道
  14.             ChannelServices.RegisterChannel(channel, false);
  15.             // 获取远程对象引用
  16.             MyRemoteObject remoteObject = (MyRemoteObject)Activator.GetObject(typeof(MyRemoteObject), "tcp://localhost:8080/MyRemoteObject");
  17.             // 调用远程对象的方法
  18.             int result = remoteObject.Add(3, 5);
  19.             Console.WriteLine("调用远程方法结果: " + result);
  20.             Console.Read();
  21.         }
  22.     }
  23. }
复制代码
通过以上对 C# 封送和长途编程的先容,盼望能资助你深入明白这两个告急概念及其在现实开发中的应用。假如你对代码实现细节、原理有进一步的疑问,大概想要相识更多干系应用场景,接待随时互换。
回复

使用道具 举报

登录后关闭弹窗

登录参与点评抽奖  加入IT实名职场社区
去登录
快速回复 返回顶部 返回列表