添加链接
link之家
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接
相关文章推荐
无邪的丝瓜  ·  curl默认超时时间-掘金·  1 年前    · 
体贴的小刀  ·  ansible ...·  1 年前    · 

java与c++实现共享内存(linux系统)

1 年前

对于linux系统来说,共享内存分为一般共享内存和映像文件共享内存两种,但是java只能创建映像文件共享内存。所以本文就通过映像文件共享内存实现java与c++内存共享。

  1. linux使用mmap将文件映射到内存,实现c++端写入共享内存
    #include <iostream>
    #include <unistd.h>
    #include <string.h>
    #include <sys/mman.h>
    #include <fcntl.h>
    #include <stdio.h>
    using namespace std;
    struct MyData
       char name[20];
       int length;
       int age;
    void WriteMemory_MMAP()
       //定义共享文件
       char* shared_file_name = "/root/sharememory/demotest1";
       MyData share_buf = {"Tom", 180, 18};
       int fd = open(shared_file_name, O_CREAT | O_RDWR | O_TRUNC, 00777);
       if(fd < 0)
           cout << "create file error" << endl;
       size_t write_size = sizeof(share_buf);
       cout << "write_size:" << write_size << endl;
       ftruncate(fd, write_size); //重置文件大小
       //将文件映射到内存
       void *p = mmap(NULL, write_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
       //拷贝数据到共享内存
       memcpy(p, &share_buf, write_size);
       //解除映射
       munmap(p, write_size);
       close(fd);
    void ReadMemory_MMAP()
        char* shared_file_name = "/root/sharememory/demotest1";
        int fd = open(shared_file_name, O_RDONLY, 00777);
        if(fd < 0)
           cout << "open file error" << endl;
        const unsigned long buff_size = 4096;
        size_t read_size = sizeof(MyData);
        void *p = mmap(NULL, read_size, PROT_READ, MAP_SHARED, fd, 0);
        cout << "read shared data:" << endl;
        MyData* share_buffer = (MyData*)p;
        cout << share_buffer->name << " " << share_buffer->length << " " << share_buffer->age << endl;
        munmap(p, read_size);
        close(fd);
    int main(int argc, char** argv) 
        WriteMemory_MMAP();
        getchar();
        return 0;
    }

2. java提供的类MappedByteBuffer为我们提供了实现共享内存的方法,该缓冲区其实是一个磁盘文件的内存映像。两者变化将保持同步,即内存数据发生变化会马上反映到磁盘文件中,这样会有效的保证共享内存的实现。

将共享内存和磁盘文件创建联系的是文件通道类:FileChannel。该类的加入是JDK为了统一对外部设备(文件、网络接口等)的访问方法,而且增强了多线程对同一文件进行存取的安全性。例如读写操作做成统一的read和write。这里只是用它来创建共享内存,它创建了共享内存和磁盘文件之间的一个通道。

打开一个文件创建一个文件通道能够用RandomAccessFile类中的方法getChannel。该方法将直接返回一个文件通道。该文件通道因为对应的文件设为随机存取文件,一方面能够进行读写两种操作,另一方面使用它不会破坏映像文件的内容。

package com.sharemem;
import java.io.*;
import java.nio.ByteBuffer;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.channels.FileLock;
import java.util.Properties;
class ShareStruct
    private byte[] recv = new byte[1024*1024];
    private byte[] name = new byte[40];
    private int age;
    private int length;
    public ShareStruct(byte[] recv)
        this.recv = recv;
    public void ParseStruct()
        InputStream in_withcode;
        try {
            in_withcode = new ByteArrayInputStream(recv);
            DataInputStream inputStream = new DataInputStream(in_withcode);
            inputStream.read(name, 0, 20);
            System.out.println("name:" + toStr(name, 0, 20));
            age = inputStream.readInt();
            System.out.println("age:" + int_EndianBigtoLittle(age));
            length = inputStream.readInt();
            System.out.println("length:" + int_EndianBigtoLittle(length));
        } catch (IOException e){
            e.printStackTrace();
     * 将byte数组转为String
     * @param valArr 待转换的byte数组
     * @param startpoint 待转换的byte数组开始位置
     * @param maxLen 待转换的byte数组长度
     * @return
    private static String toStr(byte[] valArr, int startpoint, int maxLen)
        int index = 0;
        while (index + startpoint < valArr.length && index < maxLen)
            if(valArr[index + startpoint] == 0)
                break;
            index++;
        byte[] temp = new byte[index];
        System.arraycopy(valArr, startpoint, temp, 0, index);
        return new String(temp);
     * 大端数据转小端数据
     * @param value
     * @return 将读取的数据转为小端模式下的数据
    private static int int_EndianBigtoLittle(int value)
        byte[] src = new byte[4];
        src[0] = (byte) ((value >> 24) & 0xFF);
        src[1] = (byte) ((value >> 16) & 0xFF);
        src[2] = (byte) ((value >> 8) & 0xFF);
        src[3] = (byte) (value & 0xFF);
        return (int)((src[0]&0xff)|((src[1]&0xFF)<<8)|((src[2]&0xFF)<<16)|((src[3]&0xFF)<<24));
     * 读取4位,并转化为无符号的4位整数
     * @param value
     * @return 将读取的数据转为小端模式下的数据
    private static long Long_EndianBigtoLittle(int value)
        byte[] src = new byte[4];
        src[0] = (byte) ((value >> 24) & 0xFF);
        src[1] = (byte) ((value >> 16) & 0xFF);
        src[2] = (byte) ((value >> 8) & 0xFF);
        src[3] = (byte) ((value) & 0xFF);
        return (long) ((src[0]&0xFF)|((src[1]&0xFF)<<8)|((src[2]&0xFF)<<16)|((src[3]&0xFF)<<24))&0xFFFFFFFFl;
     * 大端数据转小端数据
     * @param value
     * @return 将读取的数据转为小端模式下的数据
    private static float Float_EndianBigtoLittle(int[] value)
        if(value == null || value.length != 4)
            throw new IllegalArgumentException("value数组必须不为空,并且是4位");
        int i = ((value[0]&0xFF)|((value[1]&0xFF)<<8)|((value[2]&0xFF)<<16)|((value[3]&0xFF)<<24));
        return Float.intBitsToFloat(i);
     * 读2位数据,转为无符号数据
     * @param value
     * @return 将读取的数据转为小端模式下的数据
    private static int uShort_EndianBigtoLittle(int value)
        byte[] src = new byte[2];
        src[0] = (byte) ((value>>8)&0xFF);
        src[1] = (byte) ((value)&0xFF);
        return (int) ((src[0]&0xFF)|((src[1]&0xFF)<<8));
    private static int vtolh(byte[] bArr)
        int n = 0;
        for(int i = 0; i < bArr.length&&i < 4; i++)
            int left = i * 8;
            n += (bArr[i] << left);
        return n;
public class ShareMemory
    int flen = 1024*1024;             //开辟共享内存大小
    int fsize = 0;                    //文件的实际大小
    String shareFileName;             //共享内存文件名
    String sharePath;                 //共享内存路径
    MappedByteBuffer mapBuf = null;   //定义共享内存缓冲区
    FileChannel fc = null;            //定义相应文件通道
    FileLock fl = null;               //定义文件区域锁定标记
    Properties p = null;
    RandomAccessFile RAFile = null;   //定义一个随机存取文件对象
    public ShareMemory(String sp, String sf)
        this.shareFileName = sf;
        this.sharePath = sp;
            //获得一个只读的随机存取文件对象,“rw”打开以便读取和写入。如果该文件尚不存在,则尝试创建该文件
            RAFile = new RandomAccessFile(this.sharePath + this.shareFileName, "rw");
            //获取相应的文件通道
            fc = RAFile.getChannel();
            //获取实际文件的大小
            fsize = (int)fc.size();
            if(fsize < flen)
                byte bb[] = new byte[flen - fsize];
                //创建字节缓冲区
                ByteBuffer bf = ByteBuffer.wrap(bb);
                bf.clear();
                //设置此通道的文件位置
                fc.position(fsize);
                //将字节序从给定的缓冲区写入此通道
                fc.write(bf);
                fc.force(false);
                fsize = flen;
            //将此通道的文件区域直接映射到内存中
            mapBuf = fc.map(FileChannel.MapMode.READ_WRITE, 0, fsize);
        catch (IOException e)
            e.printStackTrace();
     * @param ps    锁定区域开始的位置;必须为非负数
     * @param len   锁定区域的大小;必须为非负数
     * @param buff  写入的数据
     * @return
    public synchronized int write(int ps, int len, byte[] buff)
        if(ps >= fsize || ps + len >= fsize)
            return 0;
        //定义文件区域锁定的标记
        FileLock fl = null;
            //获取此通道的文件给定区域上的锁定
            fl = fc.lock(ps, len, false);
            if(fl != null)
                mapBuf.position(ps);
                ByteBuffer bf1 = ByteBuffer.wrap(buff);
                mapBuf.put(bf1);
                //释放此锁定
                fl.release();
        catch (Exception e)
            if(fl != null)
                    fl.release();
                catch (IOException el)
                    System.out.println(el.toString());
            return 0;
        return 0;
     * @param ps
     * @param len
     * @param buff
     * @return
    public synchronized int read(int ps, int len, byte[] buff)
        if(ps >= fsize)
            return 0;
        FileLock fl = null;
            fl = fc.lock(ps, len, false);
            if(fl != null)
                mapBuf.position(ps);
                if(mapBuf.remaining() < len)
                    len = mapBuf.remaining();
                if(len > 0)
                    mapBuf.get(buff, 0, len);
                fl.release();
                return len;
        catch (Exception e)
            if(fl != null)
                    fl.release();
                catch (IOException el)
                    System.out.println(el.toString());
            return 0;
        return 0;
     * 完成,关闭相关操作
     * @throws Throwable
    protected void finalize() throws Throwable
        if(fc != null)
            try {
                fc.close();
            } catch (IOException e) {
                System.out.println(e.toString());
            fc = null;
        if(RAFile != null)
            try {
                RAFile.close();
            } catch (IOException e) {
                System.out.println(e.toString());
            RAFile = null;
        mapBuf = null;
     * 关闭共享内存操作
    public synchronized void closeSMFile()
        if(fc != null)
            try {
                fc.close();
            } catch (IOException e) {
                System.out.println(e.toString());
            fc = null;
        if(RAFile != null)
            try {
                RAFile.close();
            } catch (IOException e) {
                System.out.println(e.toString());
            RAFile = null;
        mapBuf = null;
     * 检查退出,共享内存第一位是1退出,是0不退出
     * @return true-成功 false-失败
    public synchronized boolean checkToExit()
        byte bb[] = new byte[1];
        if(read(1,1, bb) > 0)
            if(bb[0] == 1)
                return true;
        return false;
     * 复位退出
    public synchronized void resetExit()
        byte bb[] = new byte[1];
        bb[0] = 0;
        write(1, 1, bb);
    public synchronized void toExit()
        byte bb[] = new byte[1];
        bb[0] = 1;
        write(1, 1, bb);
    public static void main(String args[]) throws Exception
        ShareMemory sm = new ShareMemory("/root/sharememory/", "demotest1");
        byte[] b = new byte[100];