C++与Java进程间通信:字符串数据传递实现入门问询
Hey, let's figure out how to get that C++ message string into your Java Recv class using IPC. I'll walk you through two practical approaches—named pipes (simple, no extra dependencies) and shared memory (faster, for high-throughput scenarios)—with code you can drop into your projects.
一、Named Pipes(命名管道)方案
Named pipes work across processes (and even across languages) because they act like a file-based communication channel. Perfect for straightforward string passing.
C++ 发送端代码
This creates the pipe and writes your message variable to it. It handles both Windows and Linux:
#include <iostream> #include <fstream> #include <string> #ifdef _WIN32 #include <windows.h> #define PIPE_NAME "\\\\.\\pipe\\JavaCppPipe" #else #include <fcntl.h> #include <sys/stat.h> #include <unistd.h> #define PIPE_NAME "/tmp/JavaCppPipe" #endif int main() { std::string message = "Hello from C++!"; // Your target message variable #ifdef _WIN32 // Create named pipe on Windows HANDLE hPipe = CreateNamedPipe( PIPE_NAME, PIPE_ACCESS_OUTBOUND, PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT, PIPE_UNLIMITED_INSTANCES, 0, 0, 0, NULL ); if (hPipe == INVALID_HANDLE_VALUE) { std::cerr << "Failed to create pipe!" << std::endl; return 1; } // Wait for Java to connect if (!ConnectNamedPipe(hPipe, NULL)) { std::cerr << "Failed to connect to pipe!" << std::endl; CloseHandle(hPipe); return 1; } // Write message to pipe (include null terminator) DWORD bytesWritten; BOOL success = WriteFile( hPipe, message.c_str(), message.size() + 1, &bytesWritten, NULL ); if (!success) { std::cerr << "Failed to write to pipe!" << std::endl; CloseHandle(hPipe); return 1; } CloseHandle(hPipe); #else // Create named pipe on Linux mkfifo(PIPE_NAME, 0666); int fd = open(PIPE_NAME, O_WRONLY); if (fd == -1) { std::cerr << "Failed to open pipe!" << std::endl; return 1; } // Write message write(fd, message.c_str(), message.size() + 1); close(fd); unlink(PIPE_NAME); // Clean up pipe after use #endif return 0; }
Java 接收端(修改你的Recv类)
This reads from the pipe and populates your Java message variable:
import java.io.IOException; import java.io.RandomAccessFile; import java.nio.charset.StandardCharsets; public class Recv { public static String message; // Your target variable to populate public static void main(String[] args) { String pipeName; // Handle cross-platform pipe name differences if (System.getProperty("os.name").toLowerCase().contains("win")) { pipeName = "\\\\.\\pipe\\JavaCppPipe"; } else { pipeName = "/tmp/JavaCppPipe"; } try (RandomAccessFile pipe = new RandomAccessFile(pipeName, "r")) { byte[] buffer = new byte[1024]; int bytesRead = pipe.read(buffer); if (bytesRead > 0) { // Convert bytes to string and trim any extra nulls message = new String(buffer, 0, bytesRead, StandardCharsets.UTF_8).trim(); System.out.println("Received from C++: " + message); } } catch (IOException e) { e.printStackTrace(); } } }
Pro Tip: Run the Java program first (so it waits for the pipe connection), then start the C++ program to send the message.
二、Shared Memory(共享内存)方案
Shared memory is faster because it skips data copying between processes—both programs read/write directly to the same memory block. Java needs a little help here (we'll use JNA to call system APIs).
C++ 写入端代码
Creates a shared memory block and writes your message to it:
#include <iostream> #include <string> #ifdef _WIN32 #include <windows.h> #define SHM_NAME "JavaCppSharedMem" #else #include <sys/ipc.h> #include <sys/shm.h> #include <unistd.h> #define SHM_KEY 12345 #define SHM_SIZE 1024 #endif int main() { std::string message = "Hello from C++ Shared Memory!"; #ifdef _WIN32 // Create shared memory on Windows HANDLE hMapFile = CreateFileMapping( INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, 1024, SHM_NAME ); if (hMapFile == NULL) { std::cerr << "Failed to create shared memory!" << std::endl; return 1; } char* pBuf = (char*)MapViewOfFile( hMapFile, FILE_MAP_ALL_ACCESS, 0, 0, 1024 ); if (pBuf == NULL) { std::cerr << "Failed to map shared memory!" << std::endl; CloseHandle(hMapFile); return 1; } // Copy message to shared memory strcpy(pBuf, message.c_str()); // Wait for Java to read (replace with semaphores in production) std::cout << "Data written to shared memory. Press Enter to exit..." << std::endl; std::cin.get(); UnmapViewOfFile(pBuf); CloseHandle(hMapFile); #else // Create shared memory on Linux int shmid = shmget(SHM_KEY, SHM_SIZE, IPC_CREAT | 0666); if (shmid == -1) { std::cerr << "Failed to get shared memory ID!" << std::endl; return 1; } char* pBuf = (char*)shmat(shmid, NULL, 0); if (pBuf == (char*)-1) { std::cerr << "Failed to attach to shared memory!" << std::endl; return 1; } // Copy message to shared memory strcpy(pBuf, message.c_str()); // Wait for Java to read std::cout << "Data written. Press Enter to clean up..." << std::endl; std::cin.get(); shmdt(pBuf); shmctl(shmid, IPC_RMID, NULL); // Clean up shared memory #endif return 0; }
Java 接收端(修改你的Recv类)
We'll use JNA (Java Native Access) to call system-level shared memory functions. First, add the JNA dependency if you're using Maven:
<dependency> <groupId>net.java.dev.jna</groupId> <artifactId>jna</artifactId> <version>5.13.0</version> </dependency>
Then update your Recv class:
import com.sun.jna.Library; import com.sun.jna.Native; import com.sun.jna.Pointer; import com.sun.jna.platform.win32.Kernel32; import com.sun.jna.platform.win32.WinNT; import java.nio.charset.StandardCharsets; public class Recv { public static String message; // Interface for Linux C library functions interface CLibrary extends Library { CLibrary INSTANCE = Native.load("c", CLibrary.class); int shmget(int key, int size, int flag); Pointer shmat(int shmid, Pointer addr, int flag); int shmdt(Pointer shmaddr); int shmctl(int shmid, int cmd, Pointer buf); } public static void main(String[] args) { if (System.getProperty("os.name").toLowerCase().contains("win")) { // Read shared memory on Windows String shmName = "JavaCppSharedMem"; WinNT.HANDLE hMapFile = Kernel32.INSTANCE.OpenFileMapping( Kernel32.FILE_MAP_ALL_ACCESS, false, shmName ); if (hMapFile == null) { System.err.println("Failed to open shared memory!"); return; } Pointer pBuf = Kernel32.INSTANCE.MapViewOfFile( hMapFile, Kernel32.FILE_MAP_ALL_ACCESS, 0, 0, 1024 ); if (pBuf == null) { System.err.println("Failed to map shared memory!"); Kernel32.INSTANCE.CloseHandle(hMapFile); return; } // Read string from shared memory message = pBuf.getString(0, StandardCharsets.UTF_8.name()); System.out.println("Received from shared memory: " + message); Kernel32.INSTANCE.UnmapViewOfFile(pBuf); Kernel32.INSTANCE.CloseHandle(hMapFile); } else { // Read shared memory on Linux final int SHM_KEY = 12345; int shmid = CLibrary.INSTANCE.shmget(SHM_KEY, 1024, 0666); if (shmid == -1) { System.err.println("Failed to get shared memory ID!"); return; } Pointer pBuf = CLibrary.INSTANCE.shmat(shmid, null, 0); if (pBuf == null) { System.err.println("Failed to attach to shared memory!"); return; } message = pBuf.getString(0); System.out.println("Received from shared memory: " + message); CLibrary.INSTANCE.shmdt(pBuf); } } }
Important: Shared memory doesn't have built-in synchronization. In production, use semaphores or mutexes to avoid race conditions (the example uses user input as a simple wait mechanism).
Quick Recommendation
- Use named pipes if you want simplicity, no extra dependencies, and don't need maximum performance.
- Use shared memory if you need fast, high-throughput communication (just remember to handle synchronization!).
内容的提问来源于stack exchange,提问作者Jas

