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

开源 C# 快速开发(十四)进程--内存映射

         文章的目的为了记录使用C# 开发学习的经历。开发流程和要点有些记忆模糊,赶紧记录,防止忘记。

 相关链接:

开源 C# 快速开发(一)基础知识

开源 C# 快速开发(二)基础控件

开源 C# 快速开发(三)复杂控件

开源 C# 快速开发(四)自定义控件--波形图

开源 C# 快速开发(五)自定义控件--仪表盘

开源 C# 快速开发(六)自定义控件--圆环

开源 C# 快速开发(七)通讯--串口

开源 C# 快速开发(八)通讯--Tcp服务器端

开源 C# 快速开发(九)通讯--Tcp客户端

开源 C# 快速开发(十)通讯--http客户端

开源 C# 快速开发(十一)线程

开源 C# 快速开发(十二)进程监控

推荐链接:

开源 C# .net mvc 开发(一)WEB搭建_c#部署web程序-CSDN博客

开源 C# .net mvc 开发(二)网站快速搭建_c#网站开发-CSDN博客

开源 C# .net mvc 开发(三)WEB内外网访问-CSDN博客

开源 C# .net mvc 开发(四)工程结构、页面提交以及显示-CSDN博客

开源 C# .net mvc 开发(五)常用代码快速开发_c# mvc开发-CSDN博客

开源 C# .net mvc 开发(六)发送邮件、定时以及CMD编程-CSDN博客

开源 C# .net mvc 开发(七)动态图片、动态表格和json数据生成-CSDN博客

开源 C# .net mvc 开发(八)IIS Express轻量化Web服务器的配置和使用-CSDN博客

开源 C# .net mvc 开发(九)websocket--服务器与客户端的实时通信-CSDN博客

本章节主要内容是:内存映射文件在C#进程间进行的数据通信,服务器端和客户端之间的通讯。

内存映射文件(Memory-Mapped Files)是一种将磁盘文件或共享内存区域直接映射到进程虚拟地址空间的技术。通过这种技术,应用程序可以像访问普通内存一样访问文件内容,而无需使用传统的文件I/O操作。

目录:

1.源码分析

2.所有源码

3.效果演示

一、源码分析

服务器端代码分析

1. 服务器初始化 InitializeServer()

private void InitializeServer()
{try{// 创建或打开内存映射文件mmf = MemoryMappedFile.CreateOrOpen(MapName, Capacity);accessor = mmf.CreateViewAccessor();// 初始化共享内存:在位置0写入0(数据长度)accessor.Write(0, 0);// 启动读取线程isRunning = true;readThread = new Thread(ReadFromSharedMemory);readThread.IsBackground = true;  // 设为后台线程,主线程退出时自动终止readThread.Start();UpdateStatus("服务器已启动 - 等待客户端连接...");}catch (Exception ex){MessageBox.Show($"服务器启动失败: {ex.Message}");}
}


关键点:

CreateOrOpen:如果文件不存在则创建,存在则打开

前4字节用于存储数据长度,初始化为0

启动后台线程持续监听消息

2. 读取线程函数 ReadFromSharedMemory()

private void ReadFromSharedMemory()
{while (isRunning)  // 循环直到停止标志为false{try{// 读取前4字节获取数据长度int dataLength = accessor.ReadInt32(0);if (dataLength > 0)  // 有数据需要读取{// 读取实际数据(从第4字节开始)byte[] buffer = new byte[dataLength];accessor.ReadArray(4, buffer, 0, dataLength);string receivedMessage = Encoding.UTF8.GetString(buffer);// 在UI线程上安全更新界面Invoke(new Action(() =>{lstReceivedMessages.Items.Add($"[{DateTime.Now:HH:mm:ss}] 收到: {receivedMessage}");lstReceivedMessages.TopIndex = lstReceivedMessages.Items.Count - 1;}));// 清空数据长度标记,表示数据已处理accessor.Write(0, 0);}Thread.Sleep(100); // 降低CPU使用率}catch (ThreadAbortException){break;  // 线程被中止时退出循环}catch (Exception ex){// 在UI线程显示错误信息Invoke(new Action(() => UpdateStatus($"读取错误: {ex.Message}")));Thread.Sleep(1000);}}
}


数据格式:text
[0-3字节] 数据长度 (int32)
[4-...字节] 实际数据 (UTF-8编码的字符串)


3. 发送消息 SendMessage(string message)

private void SendMessage(string message)
{if (string.IsNullOrWhiteSpace(message)){MessageBox.Show("请输入要发送的消息");return;}try{// 将字符串转换为字节数组byte[] buffer = Encoding.UTF8.GetBytes(message);int dataLength = buffer.Length;// 检查消息长度是否超出容量if (dataLength > Capacity - 4) // 减去存储长度的4字节{MessageBox.Show("消息太长,无法发送");return;}// 写入数据:先写长度,再写数据accessor.Write(0, dataLength);accessor.WriteArray(4, buffer, 0, dataLength);// 更新发送历史lstSentMessages.Items.Add($"[{DateTime.Now:HH:mm:ss}] 发送: {message}");lstSentMessages.TopIndex = lstSentMessages.Items.Count - 1;txtMessage.Clear();txtMessage.Focus();}catch (Exception ex){MessageBox.Show($"发送失败: {ex.Message}");}
}



4. 事件处理函数
btnSend_Click

private void btnSend_Click(object sender, EventArgs e)
{SendMessage(txtMessage.Text);  // 调用发送消息函数
}


txtMessage_KeyPress
 

private void txtMessage_KeyPress(object sender, KeyPressEventArgs e)
{if (e.KeyChar == (char)Keys.Enter)  // 按Enter键发送{btnSend_Click(sender, e);e.Handled = true;  // 阻止系统处理Enter键}
}


ServerForm_FormClosing

private void ServerForm_FormClosing(object sender, FormClosingEventArgs e)
{isRunning = false;           // 设置停止标志readThread?.Join(1000);      // 等待读取线程结束,最多等待1秒// 释放资源accessor?.Dispose();mmf?.Dispose();
}



5. 辅助函数 UpdateStatus(string status)

private void UpdateStatus(string status)
{lblStatus.Text = status;  // 更新状态标签
}



客户端代码分析
客户端的函数与服务器端非常相似,主要区别在于初始化部分:

1. 客户端初始化 InitializeClient()

private void InitializeClient()
{try{// 连接到现有的内存映射文件(必须已由服务器创建)mmf = MemoryMappedFile.OpenExisting(MapName);accessor = mmf.CreateViewAccessor();isRunning = true;readThread = new Thread(ReadFromSharedMemory);readThread.IsBackground = true;readThread.Start();UpdateStatus("客户端已连接");}catch (FileNotFoundException){MessageBox.Show("服务器未启动,请先启动服务器端程序");UpdateStatus("连接失败 - 服务器未启动");}catch (Exception ex){MessageBox.Show($"客户端启动失败: {ex.Message}");UpdateStatus($"连接失败: {ex.Message}");}
}


关键区别:

使用 OpenExisting 而不是 CreateOrOpen

需要处理 FileNotFoundException(服务器未启动的情况)

二、所有源码

ServerForm.cs文件源码

using System;
using System.IO;
using System.IO.MemoryMappedFiles;
using System.Text;
using System.Threading;
using System.Windows.Forms;namespace MemoryMappedFileDemo
{public partial class ServerForm : Form{private MemoryMappedFile mmf;private MemoryMappedViewAccessor accessor;private const string MapName = "MySharedMemory";private const int Capacity = 1024; // 1KB共享内存private Thread readThread;private bool isRunning = false;public ServerForm(){InitializeComponent();InitializeServer();}private void InitializeServer(){try{// 创建内存映射文件mmf = MemoryMappedFile.CreateOrOpen(MapName, Capacity);accessor = mmf.CreateViewAccessor();// 初始化共享内存accessor.Write(0, 0); // 写入数据长度isRunning = true;readThread = new Thread(ReadFromSharedMemory);readThread.IsBackground = true;readThread.Start();UpdateStatus("服务器已启动 - 等待客户端连接...");}catch (Exception ex){MessageBox.Show($"服务器启动失败: {ex.Message}");}}private void ReadFromSharedMemory(){while (isRunning){try{// 读取数据长度int dataLength = accessor.ReadInt32(0);if (dataLength > 0){// 读取实际数据byte[] buffer = new byte[dataLength];accessor.ReadArray(4, buffer, 0, dataLength);string receivedMessage = Encoding.UTF8.GetString(buffer);// 在UI线程上更新接收到的消息Invoke(new Action(() =>{lstReceivedMessages.Items.Add($"[{DateTime.Now:HH:mm:ss}] 收到: {receivedMessage}");lstReceivedMessages.TopIndex = lstReceivedMessages.Items.Count - 1;}));// 清空数据长度标记,表示数据已读取accessor.Write(0, 0);}Thread.Sleep(100); // 降低CPU使用率}catch (ThreadAbortException){break;}catch (Exception ex){Invoke(new Action(() =>UpdateStatus($"读取错误: {ex.Message}")));Thread.Sleep(1000);}}}private void btnSend_Click(object sender, EventArgs e){SendMessage(txtMessage.Text);}private void SendMessage(string message){if (string.IsNullOrWhiteSpace(message)){MessageBox.Show("请输入要发送的消息");return;}try{byte[] buffer = Encoding.UTF8.GetBytes(message);int dataLength = buffer.Length;if (dataLength > Capacity - 4) // 减去存储长度的4字节{MessageBox.Show("消息太长,无法发送");return;}// 写入数据长度和实际数据accessor.Write(0, dataLength);accessor.WriteArray(4, buffer, 0, dataLength);lstSentMessages.Items.Add($"[{DateTime.Now:HH:mm:ss}] 发送: {message}");lstSentMessages.TopIndex = lstSentMessages.Items.Count - 1;txtMessage.Clear();txtMessage.Focus();}catch (Exception ex){MessageBox.Show($"发送失败: {ex.Message}");}}private void UpdateStatus(string status){lblStatus.Text = status;}private void ServerForm_FormClosing(object sender, FormClosingEventArgs e){isRunning = false;readThread?.Join(1000);accessor?.Dispose();mmf?.Dispose();}private void txtMessage_KeyPress(object sender, KeyPressEventArgs e){if (e.KeyChar == (char)Keys.Enter){btnSend_Click(sender, e);e.Handled = true;}}#region Windows Form Designer generated codeprivate System.ComponentModel.IContainer components = null;private TextBox txtMessage;private Button btnSend;private ListBox lstReceivedMessages;private ListBox lstSentMessages;private Label lblStatus;private Label label1;private Label label2;private Label label3;protected override void Dispose(bool disposing){if (disposing && (components != null)){components.Dispose();}base.Dispose(disposing);}private void InitializeComponent(){this.txtMessage = new System.Windows.Forms.TextBox();this.btnSend = new System.Windows.Forms.Button();this.lstReceivedMessages = new System.Windows.Forms.ListBox();this.lstSentMessages = new System.Windows.Forms.ListBox();this.lblStatus = new System.Windows.Forms.Label();this.label1 = new System.Windows.Forms.Label();this.label2 = new System.Windows.Forms.Label();this.label3 = new System.Windows.Forms.Label();this.SuspendLayout();// txtMessagethis.txtMessage.Location = new System.Drawing.Point(12, 30);this.txtMessage.Name = "txtMessage";this.txtMessage.Size = new System.Drawing.Size(300, 20);this.txtMessage.TabIndex = 0;this.txtMessage.KeyPress += new System.Windows.Forms.KeyPressEventHandler(this.txtMessage_KeyPress);// btnSendthis.btnSend.Location = new System.Drawing.Point(318, 28);this.btnSend.Name = "btnSend";this.btnSend.Size = new System.Drawing.Size(75, 23);this.btnSend.TabIndex = 1;this.btnSend.Text = "发送";this.btnSend.UseVisualStyleBackColor = true;this.btnSend.Click += new System.EventHandler(this.btnSend_Click);// lstReceivedMessagesthis.lstReceivedMessages.FormattingEnabled = true;this.lstReceivedMessages.HorizontalScrollbar = true;this.lstReceivedMessages.Location = new System.Drawing.Point(12, 80);this.lstReceivedMessages.Name = "lstReceivedMessages";this.lstReceivedMessages.Size = new System.Drawing.Size(381, 160);this.lstReceivedMessages.TabIndex = 2;// lstSentMessagesthis.lstSentMessages.FormattingEnabled = true;this.lstSentMessages.HorizontalScrollbar = true;this.lstSentMessages.Location = new System.Drawing.Point(12, 270);this.lstSentMessages.Name = "lstSentMessages";this.lstSentMessages.Size = new System.Drawing.Size(381, 160);this.lstSentMessages.TabIndex = 3;// lblStatusthis.lblStatus.AutoSize = true;this.lblStatus.Location = new System.Drawing.Point(12, 450);this.lblStatus.Name = "lblStatus";this.lblStatus.Size = new System.Drawing.Size(55, 13);this.lblStatus.TabIndex = 4;this.lblStatus.Text = "状态: 离线";// label1this.label1.AutoSize = true;this.label1.Location = new System.Drawing.Point(12, 10);this.label1.Name = "label1";this.label1.Size = new System.Drawing.Size(58, 13);this.label1.TabIndex = 5;this.label1.Text = "发送消息:";// label2this.label2.AutoSize = true;this.label2.Location = new System.Drawing.Point(12, 60);this.label2.Name = "label2";this.label2.Size = new System.Drawing.Size(82, 13);this.label2.TabIndex = 6;this.label2.Text = "收到的消息:";// label3this.label3.AutoSize = true;this.label3.Location = new System.Drawing.Point(12, 250);this.label3.Name = "label3";this.label3.Size = new System.Drawing.Size(82, 13);this.label3.TabIndex = 7;this.label3.Text = "发送的消息:";// ServerFormthis.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;this.ClientSize = new System.Drawing.Size(405, 480);this.Controls.Add(this.label3);this.Controls.Add(this.label2);this.Controls.Add(this.label1);this.Controls.Add(this.lblStatus);this.Controls.Add(this.lstSentMessages);this.Controls.Add(this.lstReceivedMessages);this.Controls.Add(this.btnSend);this.Controls.Add(this.txtMessage);this.Name = "ServerForm";this.Text = "内存映射文件 - 服务器端";this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.ServerForm_FormClosing);this.ResumeLayout(false);this.PerformLayout();}#endregion}
}

ClientForm.cs文件源码

using System;
using System.IO;
using System.IO.MemoryMappedFiles;
using System.Text;
using System.Threading;
using System.Windows.Forms;namespace MemoryClientDemo
{public partial class ClientForm : Form{private MemoryMappedFile mmf;private MemoryMappedViewAccessor accessor;private const string MapName = "MySharedMemory";private const int Capacity = 1024;private Thread readThread;private bool isRunning = false;public ClientForm(){InitializeComponent();InitializeClient();}private void InitializeClient(){try{// 连接到现有的内存映射文件mmf = MemoryMappedFile.OpenExisting(MapName);accessor = mmf.CreateViewAccessor();isRunning = true;readThread = new Thread(ReadFromSharedMemory);readThread.IsBackground = true;readThread.Start();UpdateStatus("客户端已连接");}catch (FileNotFoundException){MessageBox.Show("服务器未启动,请先启动服务器端程序");UpdateStatus("连接失败 - 服务器未启动");}catch (Exception ex){MessageBox.Show($"客户端启动失败: {ex.Message}");UpdateStatus($"连接失败: {ex.Message}");}}private void ReadFromSharedMemory(){while (isRunning){try{// 读取数据长度int dataLength = accessor.ReadInt32(0);if (dataLength > 0){// 读取实际数据byte[] buffer = new byte[dataLength];accessor.ReadArray(4, buffer, 0, dataLength);string receivedMessage = Encoding.UTF8.GetString(buffer);// 在UI线程上更新接收到的消息Invoke(new Action(() =>{lstReceivedMessages.Items.Add($"[{DateTime.Now:HH:mm:ss}] 收到: {receivedMessage}");lstReceivedMessages.TopIndex = lstReceivedMessages.Items.Count - 1;}));// 清空数据长度标记,表示数据已读取accessor.Write(0, 0);}Thread.Sleep(100);}catch (ThreadAbortException){break;}catch (Exception ex){Invoke(new Action(() =>UpdateStatus($"读取错误: {ex.Message}")));Thread.Sleep(1000);}}}private void btnSend_Click(object sender, EventArgs e){SendMessage(txtMessage.Text);}private void SendMessage(string message){if (string.IsNullOrWhiteSpace(message)){MessageBox.Show("请输入要发送的消息");return;}try{byte[] buffer = Encoding.UTF8.GetBytes(message);int dataLength = buffer.Length;if (dataLength > Capacity - 4){MessageBox.Show("消息太长,无法发送");return;}// 写入数据长度和实际数据accessor.Write(0, dataLength);accessor.WriteArray(4, buffer, 0, dataLength);lstSentMessages.Items.Add($"[{DateTime.Now:HH:mm:ss}] 发送: {message}");lstSentMessages.TopIndex = lstSentMessages.Items.Count - 1;txtMessage.Clear();txtMessage.Focus();}catch (Exception ex){MessageBox.Show($"发送失败: {ex.Message}");}}private void UpdateStatus(string status){lblStatus.Text = status;}private void ClientForm_FormClosing(object sender, FormClosingEventArgs e){isRunning = false;readThread?.Join(1000);accessor?.Dispose();mmf?.Dispose();}private void txtMessage_KeyPress(object sender, KeyPressEventArgs e){if (e.KeyChar == (char)Keys.Enter){btnSend_Click(sender, e);e.Handled = true;}}#region Windows Form Designer generated codeprivate System.ComponentModel.IContainer components = null;private TextBox txtMessage;private Button btnSend;private ListBox lstReceivedMessages;private ListBox lstSentMessages;private Label lblStatus;private Label label1;private Label label2;private Label label3;protected override void Dispose(bool disposing){if (disposing && (components != null)){components.Dispose();}base.Dispose(disposing);}private void InitializeComponent(){this.txtMessage = new System.Windows.Forms.TextBox();this.btnSend = new System.Windows.Forms.Button();this.lstReceivedMessages = new System.Windows.Forms.ListBox();this.lstSentMessages = new System.Windows.Forms.ListBox();this.lblStatus = new System.Windows.Forms.Label();this.label1 = new System.Windows.Forms.Label();this.label2 = new System.Windows.Forms.Label();this.label3 = new System.Windows.Forms.Label();this.SuspendLayout();// txtMessagethis.txtMessage.Location = new System.Drawing.Point(12, 30);this.txtMessage.Name = "txtMessage";this.txtMessage.Size = new System.Drawing.Size(300, 20);this.txtMessage.TabIndex = 0;this.txtMessage.KeyPress += new System.Windows.Forms.KeyPressEventHandler(this.txtMessage_KeyPress);// btnSendthis.btnSend.Location = new System.Drawing.Point(318, 28);this.btnSend.Name = "btnSend";this.btnSend.Size = new System.Drawing.Size(75, 23);this.btnSend.TabIndex = 1;this.btnSend.Text = "发送";this.btnSend.UseVisualStyleBackColor = true;this.btnSend.Click += new System.EventHandler(this.btnSend_Click);// lstReceivedMessagesthis.lstReceivedMessages.FormattingEnabled = true;this.lstReceivedMessages.HorizontalScrollbar = true;this.lstReceivedMessages.Location = new System.Drawing.Point(12, 80);this.lstReceivedMessages.Name = "lstReceivedMessages";this.lstReceivedMessages.Size = new System.Drawing.Size(381, 160);this.lstReceivedMessages.TabIndex = 2;// lstSentMessagesthis.lstSentMessages.FormattingEnabled = true;this.lstSentMessages.HorizontalScrollbar = true;this.lstSentMessages.Location = new System.Drawing.Point(12, 270);this.lstSentMessages.Name = "lstSentMessages";this.lstSentMessages.Size = new System.Drawing.Size(381, 160);this.lstSentMessages.TabIndex = 3;// lblStatusthis.lblStatus.AutoSize = true;this.lblStatus.Location = new System.Drawing.Point(12, 450);this.lblStatus.Name = "lblStatus";this.lblStatus.Size = new System.Drawing.Size(55, 13);this.lblStatus.TabIndex = 4;this.lblStatus.Text = "状态: 离线";// label1this.label1.AutoSize = true;this.label1.Location = new System.Drawing.Point(12, 10);this.label1.Name = "label1";this.label1.Size = new System.Drawing.Size(58, 13);this.label1.TabIndex = 5;this.label1.Text = "发送消息:";// label2this.label2.AutoSize = true;this.label2.Location = new System.Drawing.Point(12, 60);this.label2.Name = "label2";this.label2.Size = new System.Drawing.Size(82, 13);this.label2.TabIndex = 6;this.label2.Text = "收到的消息:";// label3this.label3.AutoSize = true;this.label3.Location = new System.Drawing.Point(12, 250);this.label3.Name = "label3";this.label3.Size = new System.Drawing.Size(82, 13);this.label3.TabIndex = 7;this.label3.Text = "发送的消息:";// ClientFormthis.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;this.ClientSize = new System.Drawing.Size(405, 480);this.Controls.Add(this.label3);this.Controls.Add(this.label2);this.Controls.Add(this.label1);this.Controls.Add(this.lblStatus);this.Controls.Add(this.lstSentMessages);this.Controls.Add(this.lstReceivedMessages);this.Controls.Add(this.btnSend);this.Controls.Add(this.txtMessage);this.Name = "ClientForm";this.Text = "内存映射文件 - 客户端";this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.ClientForm_FormClosing);this.ResumeLayout(false);this.PerformLayout();}#endregion}
}

三、效果演示

http://www.dtcms.com/a/431599.html

相关文章:

  • ps个人网站设计江苏网页设计报价
  • 机器视觉检测中,二值化的含义以及阈值
  • 设计发明的网站域名怎么进入网址
  • 东城网站建设公司黄骅贴吧新鲜事
  • 28.CSS 3D 玻璃形态动画效果
  • 51单片机串口中断
  • 调用链监控系统 - CAT
  • 白酒公司网站的建设阜宁网站制作费用
  • 太白 网站建设高州网站建设公司
  • 怎么搭建一个博客网站wordpress信息量几百万
  • 用 【C# + Winform + MediaPipe】 实现人脸468点识别
  • C++查缺补漏《4》_时间复杂度、空间配置器和内存池、排序总结、右值引用和移动语义、函数出参和入参、类中的deafult和delete
  • wordpress 仿百度谷歌排名优化
  • 跟我学C++中级篇—non-transient异常
  • NSIS下载安装使用教程(附安装包,非常详细)
  • 怎样下载网站模板济南seo优化外包服务公司
  • 申请手机网站网站怎么做图片动态图片不显示
  • 【导航】沁恒微 RISC-V 蓝牙 入门教程目录 【快速跳转】
  • DoFoto AI 1.270.80 | 支持AI抠图、AI消除、AI照片转漫画等功能,比美图秀秀更好用
  • dt9205a数字万用表使用说明
  • 信息系统项目的质量管理(AI地铁车辆管理)
  • 爱站seo查询做外贸网站需要什么卡
  • C语言-深度剖析数据在内存中的存储
  • AI时代,我们仍然需要真实的人吗?
  • jsp网站开发实例标题栏ck播放器整合WordPress
  • 网站设计色彩搭配做网站要求高吗
  • 一级造价工程师报考条件及科目四川seo策略
  • 网站主题类型百度统计平台
  • 青岛知名网站建设哪家好成都网站建设成都网络公司
  • wordpress生成网站模版百度app官方下载