当前位置: 首页 > news >正文

C# 封送和远程编程介绍


.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 等复杂网络环境中使用。

(四)代码示例

定义远程对象
using System;
namespace RemoteObject
{public class MyRemoteObject : MarshalByRefObject{public MyRemoteObject(){}public int Add(int a, int b){return a + b;}}
}
服务器端代码
using System;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Channels.Tcp;
using RemoteObject;namespace RemoteServer
{class Program{static void Main(string[] args){// 创建TCP服务器通道,端口号为8080TcpServerChannel channel = new TcpServerChannel(8080);// 注册通道ChannelServices.RegisterChannel(channel, false);// 注册远程对象,对象URI为"MyRemoteObject",激活模式为单例RemotingConfiguration.RegisterWellKnownServiceType(typeof(MyRemoteObject), "MyRemoteObject", WellKnownObjectMode.Singleton);Console.WriteLine("服务器已启动,等待客户端连接...");Console.Read();}}
}
客户端代码
using System;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Channels.Tcp;
using RemoteObject;namespace RemoteClient
{class Program{static void Main(string[] args){// 创建TCP客户端通道TcpClientChannel channel = new TcpClientChannel();// 注册通道ChannelServices.RegisterChannel(channel, false);// 获取远程对象引用MyRemoteObject remoteObject = (MyRemoteObject)Activator.GetObject(typeof(MyRemoteObject), "tcp://localhost:8080/MyRemoteObject");// 调用远程对象的方法int result = remoteObject.Add(3, 5);Console.WriteLine("调用远程方法结果: " + result);Console.Read();}}
}

通过以上对 C# 封送和远程编程的介绍,希望能帮助你深入理解这两个重要概念及其在实际开发中的应用。如果你对代码实现细节、原理有进一步的疑问,或者想要了解更多相关应用场景,欢迎随时交流。

相关文章:

C# 封送和远程编程介绍

.NET学习资料 .NET学习资料 .NET学习资料 在 C# 编程领域中,封送(Marshaling)和远程编程(Remote Programming)是两个极为重要的概念,它们为开发者提供了与不同环境、不同进程或不同机器上的代码进行交互的…...

MybatisPlus较全常用复杂查询引例(limit、orderby、groupby、having、like...)

MyBatis-Plus 是一个 MyBatis 的增强工具,在 MyBatis 的基础上只做增强不做改变,为简化开发、提高效率而生。以下是 MyBatis-Plus 中常用复杂查询(如 LIMIT、ORDER BY、GROUP BY、HAVING、LIKE 等)的引例: 1. 环境准备…...

02.07 TCP服务器与客户端的搭建

一.思维导图 二.使用动态协议包实现服务器与客户端 1. 协议包的结构定义 首先,是协议包的结构定义。在两段代码中,pack_t结构体都被用来表示协议包: typedef struct Pack {int size; // 记录整个协议包的实际大小enum Type type; …...

Jenkins数据备份到windows FTP服务器

文章目录 背景1. 安装配置 FileZilla Server(Windows)1.1 下载并安装 FileZilla Server1.2 配置 FTP 用户和共享目录 2. 安装并配置 FTP 客户端(CentOS)2.1 在 CentOS 安装 lftp 3. 编写 Jenkins 备份脚本3.1 赋予执行权限3.2 测试…...

【R语言】卡方检验

一、定义 卡方检验是用来检验样本观测次数与理论或总体次数之间差异性的推断性统计方法,其原理是比较观测值与理论值之间的差异。两者之间的差异越小,检验的结果越不容易达到显著水平;反之,检验结果越可能达到显著水平。 二、用…...

ASP.NET Core托管服务

目录 托管服务的异常问题 托管服务中使用DI 托管服务案例:数据的定时导出 场景,代码运行在后台。比如服务器启动的时候在后台预先加载数据到缓存,每天凌晨3点把数据导出到备份数据库,每隔5秒钟在两张表之间同步一次数据。托管服…...

HarmonyOS 5.0应用开发——全局自定义弹出框openCustomDialog

【高心星出品】 文章目录 全局自定义弹出框openCustomDialog案例开发步骤完整代码 全局自定义弹出框openCustomDialog CustomDialog是自定义弹出框,可用于广告、中奖、警告、软件更新等与用户交互响应操作。开发者可以通过CustomDialogController类显示自定义弹出框…...

如何在C++ QT 程序中集成cef3开源浏览器组件去显示网页?

文章目录 1. **准备工作**1.1 下载CEF31.2 配置Qt项目2. **集成CEF3到Qt窗口**2.1 创建Qt窗口容器2.2 初始化CEF33. **处理CEF3消息循环**4. **处理多进程架构**5. **完整代码示例**`main.cpp`6. **常见问题**6.1 黑屏问题6.2 窗口嵌入失败6.3 多进程调试7.**Github源码参考**8…...

深入讲解MyBatis

1. MyBatis 的背景和优势 背景:在 Java 开发中,传统的 JDBC 操作数据库代码繁琐,需要手动管理数据库连接、编写 SQL 语句、处理结果集等,开发效率低且容易出错。MyBatis 应运而生,它通过将 SQL 语句与 Java 代码分离&a…...

使用matlab 对传递函数分析bode图和阶跃函数

如果已知一个系统的传递函数,想看一下bode图,可以通过simulink 建模,但是simulink运行起来相对比较慢,我一般都是直接通过matlab 的m语言写脚本实现。可以快速的获得结果 如 我们有一个一阶低通传递函数 syswn/(swn) 在matlab中…...

2025牛客寒假算法基础集训营5(补题)

C 小L的位运算 显然,如果两次反置的价格小于等于交换的价格,那么直接全部反置就好了。 反之,由于交换一定低于两次反置,我们尽可能用交换来消去不正确的位置。不正确的位置类型只有00,01,10,11&…...

FaceFusion如何设置公开链接和端口

有时候我们想在局域网内的其他设备上使用 FaceFusion,这时候需要设置公开链接和端口。 当你运行 FaceFusion 的时候,会发现有这样的一段提示: To create a public link, set shareTrue in launch().但是这个提示是错的,如果你查…...

神经网络常见激活函数 6-RReLU函数

文章目录 RReLU函数导函数函数和导函数图像优缺点pytorch中的RReLU函数tensorflow 中的RReLU函数 RReLU 随机修正线性单元&#xff1a;Randomized Leaky ReLU 函数导函数 RReLU函数 R R e L U { x x ≥ 0 a x x < 0 \rm RReLU \left\{ \begin{array}{} x \quad x \ge 0…...

计算机网络面经

文章目录 基础HTTPHTTP报文结构 (注意)RPC和http的区别TCPTCP报文结构(注意)IP基础 HTTP HTTP报文结构 (注意) 请求行:请求方法get/post,url,http版本 请求头:用户标识,请求体长度,类型,cookie 请求体:内容 状态行:状态码,状态消息、(http版本) 响应头:内…...

Qt:常用控件

目录 控件概述 控件体系的发展 按钮类控件 QPushButton QRadioButton QCheckBox QToolButton 显示类控件 QLabel QLCDNumber QProgressBar QCalendarWidget 输入类控件 QLineEdit QTextEdit QComboBox QSpinBox QDateEdit & QTimeEdit QDial QSlider …...

算法设计-找第二大数(C++)

一、问题描述 用于在给定的整数数组中找到 第二大值。 二、详细代码 #include<iostream> #include<limits.h> using namespace std; //初始化最大值为a[0]&#xff0c;次大值为a[1]&#xff0c;遍历一次&#xff0c;每次比较并更新最大值和次大值&#xff0c;最…...

【C++高并发服务器WebServer】-14:Select详解及实现

本文目录 一、BIO模型二、非阻塞NIO忙轮询三、IO多路复用四、Select()多路复用实现 明确一下IO多路复用的概念&#xff1a;IO多路复用能够使得程序同时监听多个文件描述符&#xff08;文件描述符fd对应的是内核读写缓冲区&#xff09;&#xff0c;能够提升程序的性能。 Linux下…...

redis项目

短信登录 这一块我们会使用redis共享session来实现 商户查询缓存 通过本章节&#xff0c;我们会理解缓存击穿&#xff0c;缓存穿透&#xff0c;缓存雪崩等问题&#xff0c;让小伙伴的对于这些概念的理解不仅仅是停留在概念上&#xff0c;更是能在代码中看到对应的内容 优惠…...

Spring统一修改RequestBody

我们编写RestController时&#xff0c;有可能多个接口使用了相同的RequestBody&#xff0c;在一些场景下需求修改传入的RequestBody的值&#xff0c;如果是每个controller中都去修改&#xff0c;代码会比较繁琐&#xff0c;最好的方式是在一个地方统一修改&#xff0c;比如将he…...

NCV4275CDT50RKG 车规级LDO线性电压调节器芯片——专为新能源汽车设计的高可靠性电源解决方案

产品概述: NCV4275CDT50RKG 是一款符合 AEC-Q100 车规认证的高性能LDO&#xff08;低压差线性稳压器&#xff09;&#xff0c;专为新能源汽车的严苛工作环境设计。该芯片支持 输出调节为 5.0 V 或 3.3 V&#xff0c;最大输出电流达 450mA&#xff0c;具备超低静态电流&#xf…...

【OSG学习笔记】Day 18: 碰撞检测与物理交互

物理引擎&#xff08;Physics Engine&#xff09; 物理引擎 是一种通过计算机模拟物理规律&#xff08;如力学、碰撞、重力、流体动力学等&#xff09;的软件工具或库。 它的核心目标是在虚拟环境中逼真地模拟物体的运动和交互&#xff0c;广泛应用于 游戏开发、动画制作、虚…...

UE5 学习系列(三)创建和移动物体

这篇博客是该系列的第三篇&#xff0c;是在之前两篇博客的基础上展开&#xff0c;主要介绍如何在操作界面中创建和拖动物体&#xff0c;这篇博客跟随的视频链接如下&#xff1a; B 站视频&#xff1a;s03-创建和移动物体 如果你不打算开之前的博客并且对UE5 比较熟的话按照以…...

(二)原型模式

原型的功能是将一个已经存在的对象作为源目标,其余对象都是通过这个源目标创建。发挥复制的作用就是原型模式的核心思想。 一、源型模式的定义 原型模式是指第二次创建对象可以通过复制已经存在的原型对象来实现,忽略对象创建过程中的其它细节。 📌 核心特点: 避免重复初…...

全志A40i android7.1 调试信息打印串口由uart0改为uart3

一&#xff0c;概述 1. 目的 将调试信息打印串口由uart0改为uart3。 2. 版本信息 Uboot版本&#xff1a;2014.07&#xff1b; Kernel版本&#xff1a;Linux-3.10&#xff1b; 二&#xff0c;Uboot 1. sys_config.fex改动 使能uart3(TX:PH00 RX:PH01)&#xff0c;并让boo…...

【Oracle】分区表

个人主页&#xff1a;Guiat 归属专栏&#xff1a;Oracle 文章目录 1. 分区表基础概述1.1 分区表的概念与优势1.2 分区类型概览1.3 分区表的工作原理 2. 范围分区 (RANGE Partitioning)2.1 基础范围分区2.1.1 按日期范围分区2.1.2 按数值范围分区 2.2 间隔分区 (INTERVAL Partit…...

Web中间件--tomcat学习

Web中间件–tomcat Java虚拟机详解 什么是JAVA虚拟机 Java虚拟机是一个抽象的计算机&#xff0c;它可以执行Java字节码。Java虚拟机是Java平台的一部分&#xff0c;Java平台由Java语言、Java API和Java虚拟机组成。Java虚拟机的主要作用是将Java字节码转换为机器代码&#x…...

Python 实现 Web 静态服务器(HTTP 协议)

目录 一、在本地启动 HTTP 服务器1. Windows 下安装 node.js1&#xff09;下载安装包2&#xff09;配置环境变量3&#xff09;安装镜像4&#xff09;node.js 的常用命令 2. 安装 http-server 服务3. 使用 http-server 开启服务1&#xff09;使用 http-server2&#xff09;详解 …...

大模型——基于Docker+DeepSeek+Dify :搭建企业级本地私有化知识库超详细教程

基于Docker+DeepSeek+Dify :搭建企业级本地私有化知识库超详细教程 下载安装Docker Docker官网:https://www.docker.com/ 自定义Docker安装路径 Docker默认安装在C盘,大小大概2.9G,做这行最忌讳的就是安装软件全装C盘,所以我调整了下安装路径。 新建安装目录:E:\MyS…...

python基础语法Ⅰ

python基础语法Ⅰ 常量和表达式变量是什么变量的语法1.定义变量使用变量 变量的类型1.整数2.浮点数(小数)3.字符串4.布尔5.其他 动态类型特征注释注释是什么注释的语法1.行注释2.文档字符串 注释的规范 常量和表达式 我们可以把python当作一个计算器&#xff0c;来进行一些算术…...

Web APIS Day01

1.声明变量const优先 那为什么一开始前面就不能用const呢&#xff0c;接下来看几个例子&#xff1a; 下面这张为什么可以用const呢&#xff1f;因为复杂数据的引用地址没变&#xff0c;数组还是数组&#xff0c;只是添加了个元素&#xff0c;本质没变&#xff0c;所以可以用con…...