C#和python端通信之使用共享内存

一、前言

    本篇主要实验通过使用共享内存实现C#端代码和python端代码之间的通信,主要目的是相较于直接传输较大的数据(例如图像数据),该方式更节省时间。

二、代码

C#端:

    创建了一个大小为1的共享内存,名为flag1,存放一个byte变量,初始写入0

    创建了一个大小为1的共享内存,名为done,存放一个byte变量,初始写入1

    创建了一个大小为1024 * 16的共享内存,名为result,存放一个string变量,初始写入""

     之后读取图像,并创建和写入至一个大小为960*640*4的共享内存,名为cam1,存放一个byte[]变量 , 然后 flag1 写入1,循环读取done内存,若为1,则将result 内存读取出为string 并显示textBox1

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

using System.Drawing.Imaging;
using System.IO.MemoryMappedFiles;
using System.Runtime.InteropServices;


namespace testShareMemory
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void test_0()
        {
            // 读取图片
            string imagePath = "E:/cshape_test/testShareMemory/001.png";
            Bitmap bitmap = new Bitmap(imagePath);

            // 确保图片大小为960x640
            if (bitmap.Width != 960 || bitmap.Height != 640)
            {
                Console.WriteLine("图片尺寸不符合要求,必须为960x640");
                return;
            }
            MemoryMappedFile mmfCam1 = MemoryMappedFile.CreateOrOpen("cam1", bitmap.Width * bitmap.Height * 4);
            MemoryMappedViewAccessor accessor = mmfCam1.CreateViewAccessor();

            BitmapData bitmapData = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);
            byte[] buffer = new byte[bitmapData.Stride * bitmapData.Height];
            Marshal.Copy(bitmapData.Scan0, buffer, 0, buffer.Length);
            accessor.WriteArray(0, buffer, 0, buffer.Length);
            bitmap.UnlockBits(bitmapData);

            // 创建共享内存 flag , 并写入1
            var flagMMF = MemoryMappedFile.CreateOrOpen("flag1", 1);
            var flagAccessor = flagMMF.CreateViewAccessor();
            byte flagToWrite = 1;
            flagAccessor.Write(0, flagToWrite);

            //创建共享内存 done , 并写入0
            var doneMMF = MemoryMappedFile.CreateOrOpen("done", 1);
            var doneAccessor = doneMMF.CreateViewAccessor();
            byte doneToWrite = 0;
            doneAccessor.Write(0, doneToWrite);

            //创建共享内存 result , 并写入""
            int res_lens = 1024 * 32;
            MemoryMappedFile mmfResult = MemoryMappedFile.CreateOrOpen("result", res_lens);
            MemoryMappedViewAccessor resAccessor = mmfResult.CreateViewAccessor();
            byte[] strBytes = Encoding.UTF8.GetBytes("");
            //resAccessor.Write(0, strBytes.Length); // 首先写入字符串长度
            resAccessor.WriteArray(0, strBytes, 0, strBytes.Length); // 然后写入字符串字节内容

            // 循环间隔1秒,读取共享内存
            bool done = false;
            int search_times = 0;
            while (!done)
            {

                byte doneValue = doneAccessor.ReadByte(0);
                byte flagValue = flagAccessor.ReadByte(0);

                if (doneValue == 1 && flagValue == 2)
                {
                    // 读取共享内存"result"
                    string result;

                    // 读取字符串长度(前4个字节)
                    int length = resAccessor.ReadInt32(0);

                    // 创建字节数组来存储字符串数据
                    byte[] buffer_str = new byte[length];

                    // 从共享内存读取字符串数据
                    resAccessor.ReadArray(4, buffer_str, 0, length);

                    // 将字节数组转换为字符串
                    string resultString = Encoding.UTF8.GetString(buffer_str);
                    textBox1.Text = "查询到的结果为: " + resultString;

                    done = true; // 设置标志,退出循环

                }
                else
                {
                    // 等待一段时间再继续轮询
                    System.Threading.Thread.Sleep(1000); // 等待1秒
                    search_times++;


                    if (search_times > 100)
                    {
                        //Console.WriteLine("查询超时!"   );
                        textBox1.Text = "查询超时!";
                        break;
                    }
                }
            }
        }

        private void Form1_Load(object sender, EventArgs e)
        {

            test_0();
        }
    }
}

python端:

    循环读取flag1共享内存,若为1,则读取cam1数据,还原为图像数据,将2写入flag1,并将json字符串data写入result内存区,将1写入done,显示图像数据

# -*- coding: utf-8 -*-
"""
Created on Tue Feb 27 17:10:01 2024

@author: WIN10
"""

import os , cv2
import numpy as np

from multiprocessing import shared_memory
import time
import struct

import json

# 创建/打开共享内存
def create_or_open_shared_memory(name, size):
    try:
        shm = shared_memory.SharedMemory(create=False, name=name)
    except FileNotFoundError:
        shm = shared_memory.SharedMemory(create=True, name=name, size=size)
    return shm

def main():

    flag_name = "flag1"
    cam1_name = "cam1"
    done_name = "done"

    # 图像大小
    width, height, channels = 960, 640, 4
    image_size = width * height * channels

    flag_shm = create_or_open_shared_memory(flag_name, size=1)  # 1个字节,用 uint8
    flag_array = np.ndarray((1,), dtype= np.uint8  , buffer=flag_shm.buf)

    done_shm = create_or_open_shared_memory(done_name, size=1)
    done_array = np.ndarray((1,), dtype=np.uint8, buffer=done_shm.buf)

    # 初始化 cam1 共享内存
    cam1_shm = create_or_open_shared_memory(cam1_name, size=image_size)
    cam1_array = np.ndarray((height, width, channels), dtype=np.uint8, buffer=cam1_shm.buf)

    res_shm =  create_or_open_shared_memory("result", size= 1024*16 )


    while True:
        if flag_array[0] == 1:
            # 读取图像数据
            image_rgba = np.copy(cam1_array)
            img  = cv2.cvtColor(image_rgba, cv2.COLOR_RGBA2RGB)  #C#端的bitmap传过来的是4通道的,应该转为3通道

            # 将 2 写入 flag
            flag_array[0] = 2

            #写入 jason字符串到 result
            data = {
                "name": "Mario",
                "age": 28,
            }
            json_str = json.dumps(data)
            json_bytes = json_str.encode('utf-8')
            res_shm.buf[:4] = struct.pack('i', len(json_bytes))
            res_shm.buf[4:4 + len(json_bytes)] = json_bytes

            done_array[0] = 1  #done 区域写入1

            # 显示读取到的图像
            cv2.imshow('Shared Memory Image', img )
            cv2.waitKey(0)

            break

        # 每隔100毫秒检测一次
        time.sleep(0.1)
 
    # 关闭共享内存
    cam1_shm.close()
    flag_shm.close()
    res_shm.close()
    done_shm.close()


if __name__=="__main__":
    main()

三、运行结果

   先运行C# ,再运行python端

python端结果,显示接受到的图像

C#端结果,显示收到python端写入的json字符串

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/751180.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

搜维尔科技:SenseGlove Nova2国内首款支持手掌心力回馈手套开售

《SenseGlove Nova 2》现正全球发行中! 搜维尔科技独家代理最新上市的 SenseGlove Nova 2 是世上首款,也是目前市面上唯一一款提供手掌力回馈的无缐VR力回馈手套,它结合了三种最先进的反馈技术,包括主动反馈、强力反馈及震动反馈&#xff0c…

【Flink metric(1)】Flink指标系统的系统性知识:获取metric以及注册自己的metric

文章目录 一. Registering metrics:向flink注册新自己的metrics1. 注册metrics2. Metric types:指标类型2.1. Counter2.2. Gauge2.3. Histogram(ing)2.4. Meter 二. Scope:指标作用域1. User Scope2. System Scope ing3. User Variables 三. Reporter ing四. System…

Linux线程互斥锁

目录 🚩看现象,说原因 🚩解决方案 🚩互斥锁 🚀关于互斥锁的理解 🚀关于原子性的理解 🚀如何理解加锁和解锁是原子的 🚩对互斥锁的简单封装 引言 大家有任何疑问,可…

昇思25天学习打卡营第4天|onereal

今天学习的内容是:ResNet50迁移学习 以下内容拷贝至教程,实话实话看不懂,迷迷糊糊都运行jupyter里的代码。走完程序,训练生成了一些图片。 ResNet50迁移学习 在实际应用场景中,由于训练数据集不足,所以很少…

python OpenCV 库中的 cv2.Canny() 函数来对图像进行边缘检测,并显示检测到的边缘特征

import cv2# 加载图像 image cv2.imread(4.png)# 使用 Canny 边缘检测算法提取边缘特征 edges cv2.Canny(image, 100, 200)# 显示边缘特征 cv2.imshow(Edges, edges) cv2.waitKey(0) cv2.destroyAllWindows() 代码解析: 导入 OpenCV 库: import cv2加…

【十】【QT开发应用】QT中文乱码解决方案

QT中文乱码解决方案 粘贴代码导致的乱码 粘贴别人的代码时,在记事本里面"过一遍",然后再粘贴到QTCreator 使用u8 配置QT 不使用QT使用VS QT自选编码格式 结尾 最后,感谢您阅读我的文章,希望这些内容能够对您有所启发和帮助。如果您有任何问…

新能源汽车CAN总线故障定位与干扰排除的几个方法

CAN总线是目前最受欢迎的现场总线之一,在新能源车中有广泛应用。新能源车的CAN总线故障和隐患将影响驾驶体验甚至行车安全,如何进行CAN总线故障定位及干扰排除呢? 目前,国内机动车保有量已经突破三亿大关。由于大量的燃油车带来严峻的环境问题,因此全面禁售燃油车的日程在…

C语言笔记26 •顺序表应用•

基于动态顺序表实现通讯录项目 1.通讯录其实也就是顺序表,就是把里面存的数据类型变了一下 ,所以有一些方法对于顺序表适用,对于通讯录也是适用的(初始化,销毁,内存空间扩容)。 2.要用到顺序表…

Ngnix内存池——高并发实现高效内存管理

目录 一、高并发下传统方式的弊端 1、常用的内存操作函数 2、弊端一 3、弊端二 4、弊端三 5、弊端四 二、弊端解决之道 1、内存管理维度分析 2、内存管理组件选型 三、高并发内存管理最佳实践 1、内存池技术 2、内存池如何解决弊端 3、高并发内存池如何实现 四、…

springboot+vue+mysql+mybatis 二手交易平台

springbootvuemysqlmybatis 二手交易平台 相关技术 javaspringbootmybatismysqlvueelementui

十常侍乱政 | 第2集 | 愿领精兵五千,斩关入内,册立新君,诛杀宦党,扫清朝廷,以安天下 | 三国演义 | 逐鹿群雄

🙋大家好!我是毛毛张! 🌈个人首页: 神马都会亿点点的毛毛张 📌这篇博客是毛毛张分享三国演义文学剧本中的经典台词和语句,本篇分享的是《三国演义》第Ⅰ部分《群雄逐鹿》的第2️⃣集《十常侍乱政治》&am…

DigitalOcean Droplet 云主机新增内置第五代 Xeon CPU 机型

DigitalOcean 近期宣布,在其高级 CPU 服务器(Premium CPU-Optimized Droplet)队列中引入英特尔第五代Xeon可扩展处理器(代号为 Emerald Rapids)。作为英特尔产品线中的最新一代用于数据中心工作负载的处理器&#xff0…

干涉阵型成图参数记录【robust】

robust 这个玩意经常忘记,就是取2的时候是更加显示大尺度的结构,取-2更加显示小尺度结果,一般取0就是正常就好了

数学建模--lingo解决线性规划问题~~灵敏度分析的认识

目录 1.线性规划问题举隅 (1)问题介绍 (2)问题分析 (3)灵敏度分析 (4)方法缺陷 (5)可行域&凸集 2.lingo的简单认识 (1)默认…

Halcon 如何根据特征过滤区域和XLD

一 如何跟进特征过滤区域和XLD dev_open_window(0,0,512,512,black,WindowHandle)read_image(Image,fabrik)threshold(Image,Region,128,255)connection(Region,ConnectedRegions)*根据面积范围[8000,9000] dev_display(Image)select_shape(ConnectedRegions,SelectedRegions,…

数据结构速成--树和二叉树

由于是速成专题,因此内容不会十分全面,只会涵盖考试重点,各学校课程要求不同 ,大家可以按照考纲复习,不全面的内容,可以看一下小编主页数据结构初阶的内容,找到对应专题详细学习一下。 气死了…

springboot + Vue前后端项目(第二十记)

项目实战第二十记 写在前面1. 高德地图官网2. 开发文档3. 集成高德地图3.1 在public文件夹下创建config.js3.2 index.html(在项目启动文件中引入外部的js)3.3 点标记(用点标记当前位置)3.4 信息窗体(点击当前位置&…

简易深度学习(1)深入分析神经元及多层感知机

一、神经元 单个神经元结构其实可以认为是一个线性回归模型。例如下图中 该神经元输入为三个特征(x1,x2,x3),为了方便理解,大家可以认为每条线上都有一个权重和特征对应(w1,w2&…

麒麟系统安装MySQL

搞了一整天,终于搞定了,记录一下。 一、背景 项目的原因,基于JeecgBoot开发的系统需要国产化支持,这就需要在电脑上安装MySQL等支撑软件。 国产化项目的操作系统多是麒麟系统,我的系统如下: arm64架构。…

ISSCC论文详解2024 34.2——双端口设计实现高面积利用的浮点/整数存算

本文将要介绍的文献主题为浮点存内计算,题目为《A 16nm 96Kb Integer/Floating-Point Dual-Mode-Gain-CellComputing-in-Memory Macro Achieving 73.3-163.3TOPS/W and 33.2-91.2TFLOPS/W for AI-Edge Devices》,下面本文将从文章基本信息与背景知识、创…