How to connect a C/C++ process to a Java application
A question recently came up in the lab on how to connect a Java visualization
to a C process, after a bit of thought I discovered that there aren't too many sources
that have documented methods so here are a few I came up with that work along with example code.
The first and probably the easiest method on Linux/Unix based machines is to use a FIFO.
mkfifo is available
on OS X, Linux and probably on Cygwin (I haven't confirmed this). Using a pipe created with mkfifo
from both the C and Java standpoint is as easy as opening and closing a regular file. To begin
the process we start off by typing
where pipename is the name we would like to give our FIFO.
Next we have to set up the C and Java executables, the example program
below reads in numbers from ap.txt then averages them in the compiled code
and sends the result to the Java VM application to be printed.
The Java process on the other hand changes to read from stdin input stream.
Modifications to Java Code above:
The full code base can be downloaded from:
As before change directory to the javaiopipes directory, run the same make options
as before only this time no FIFO is created. To run the two applications we only need to
invoke the C process by typing:
Once the process runs, the message JAVA SIDE: Total: xxx, Integers:
xxx, Average: xxx should appear. The complete process is illustrated
Pipe with Data Stream Method
A third method is a slight modification of the second method. We still use
popen but in this case we send data as raw bits instead of ascii encoded
strings. Java reads numbers in big-endian format (see what is endianness) whereas C/C++ reads them
in little-endian format (at least on x86 architectures) so we have a choice of
either converting the numbers going into the pipe first to big-endian or
converting them on the Java side once they are pulled out of the pipe. In
my code example I've chosen to use the C method htonl() to convert the
byte order in C.
C application side:
From the code we see that we generate two random unsigned 32-bit
values, convert the endianness using
and then write the values to the pipe using fwrite. I've used
htonl, however you could just as easily use
however I've had issues using endian.h on OS X. This operation would be
more efficient if I added the two 32-bit values into one 64-bit vector
however for the sake of clarity I left the two writes.
Java application side:
The Java implementation reads in a list of two integers at a time and
stores them in an ArrayList data structure. This method can be
generalized all Java data types, however care must be taken when sending
Java unsigned values since Java only has signed types.
To run the example change the directory to javaio_pipes2 then type:
Once c_app is executed it will open a pipe using popen() to the Java
application then send through pairs of 32-bit values which are then read
and stored in an output log "java_output_log.csv" and "c_output_log.csv"
to convince doubters that this works you can run
and these two should match.
We've seen that OS level pipes and FIFOs are useful to communicate between the
JVM and a compiled (C/C++) process. These principles can easily be applied
to other language types (which is why I chose to highlight them). Another (perhaps
more performance oriented) way to communicate is through POSIX shared memory,
and it follows the same path as the last example. One complication with shared
memory is the platform specific location in which you'll open it (e.g., OS X, typically
leaves the SHM file handles within the current working directory, whereas Linux will
put the SHM handle in /dev/shm by default). If you want to try out
the shared memory approach, check out the simplified SHM library from GitHub
(https://github.com/jonathan-beard/shm), and integrate it with your project. You'll have to open it
from the Java side like a normal file and parse the input. If I get time I'll
update this tutorial with a Java FIFO example to make this more concrete. In
the interim feel free to drop me a line and suggest improvements.