java与c++实现共享内存(linux系统)
1 年前
对于linux系统来说,共享内存分为一般共享内存和映像文件共享内存两种,但是java只能创建映像文件共享内存。所以本文就通过映像文件共享内存实现java与c++内存共享。
- 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];