You have a number of options. Since you are using Linux you could use UNIX domain sockets. Or, you could serialise the data as ASCII or JSon or some other format and feed it through a pipe, SHM (shared memory segment), message queue, DBUS or similar. It's worth thinking about what sort of data you have, as these IPC mechanisms have different performance characteristics. There's a draft USENIX paper with a good analysis of the various trade-offs that is worth reading.
Since you say (in the comments to this answer) that you prefer to use SHM, here are some code samples to start you off. Using the Python posix_ipc library:
import posix_ipc # POSIX-specific IPC
import mmap # From Python stdlib
class SharedMemory(object):
"""Python interface to shared memory.
The create argument tells the object to create a new SHM object,
rather than attaching to an existing one.
"""
def __init__(self, name, size=posix_ipc.PAGE_SIZE, create=True):
self.name = name
self.size = size
if create:
memory = posix_ipc.SharedMemory(self.name, posix_ipc.O_CREX,
size=self.size)
else:
memory = posix_ipc.SharedMemory(self.name)
self.mapfile = mmap.mmap(memory.fd, memory.size)
os.close(memory.fd)
return
def put(self, item):
"""Put item in shared memory.
"""
# TODO: Deal with the case where len(item) > size(self.mapfile)
# TODO: Guard this method with a named semaphore
self.mapfile.seek(0)
pickle.dump(item, self.mapfile, protocol=2)
return
def get(self):
"""Get a Python object from shared memory.
"""
# TODO: Deal with the case where len(item) > size(self.mapfile)
# TODO: Guard this method with a named semaphore
self.mapfile.seek(0)
return pickle.load(self.mapfile)
def __del__(self):
try:
self.mapfile.close()
memory = posix_ipc.SharedMemory(self.name)
memory.unlink()
except:
pass
return
For the Java side you want to create the same class, despite what I said in the comments JTux seems to provide the equivalent functionality and the API you need is in UPosixIPC class.
The code below is an outline of the sort of thing you need to implement. However, there are several things missing -- exception handling is the obvious one, also some flags (find them in UConstant), and you'll want to add in a semaphore to guard the put / get methods. However, this should set you on the right track. Remember that an mmap or memory-mapped file is a file-like interface to a segment of RAM. So, you can use its file descriptor as if it were the fd of a normal file.
import jtux.*;
class SHM {
private String name;
private int size;
private long semaphore;
private long mapfile; // File descriptor for mmap file
/* Lookup flags and perms in your system docs */
public SHM(String name, int size, boolean create, int flags, int perms) {
this.name = name;
this.size = size;
int shm;
if (create) {
flags = flags | UConstant.O_CREAT;
shm = UPosixIPC.shm_open(name, flags, UConstant.O_RDWR);
} else {
shm = UPosixIPC.shm_open(name, flags, UConstant.O_RDWR);
}
this.mapfile = UPosixIPC.mmap(..., this.size, ..., flags, shm, 0);
return;
}
public void put(String item) {
UFile.lseek(this.mapfile(this.mapfile, 0, 0));
UFile.write(item.getBytes(), this.mapfile);
return;
}
public String get() {
UFile.lseek(this.mapfile(this.mapfile, 0, 0));
byte[] buffer = new byte[this.size];
UFile.read(this.mapfile, buffer, buffer.length);
return new String(buffer);
}
public void finalize() {
UPosix.shm_unlink(this.name);
UPosix.munmap(this.mapfile, this.size);
}
}
Answer from snim2 on Stack OverflowYou have a number of options. Since you are using Linux you could use UNIX domain sockets. Or, you could serialise the data as ASCII or JSon or some other format and feed it through a pipe, SHM (shared memory segment), message queue, DBUS or similar. It's worth thinking about what sort of data you have, as these IPC mechanisms have different performance characteristics. There's a draft USENIX paper with a good analysis of the various trade-offs that is worth reading.
Since you say (in the comments to this answer) that you prefer to use SHM, here are some code samples to start you off. Using the Python posix_ipc library:
import posix_ipc # POSIX-specific IPC
import mmap # From Python stdlib
class SharedMemory(object):
"""Python interface to shared memory.
The create argument tells the object to create a new SHM object,
rather than attaching to an existing one.
"""
def __init__(self, name, size=posix_ipc.PAGE_SIZE, create=True):
self.name = name
self.size = size
if create:
memory = posix_ipc.SharedMemory(self.name, posix_ipc.O_CREX,
size=self.size)
else:
memory = posix_ipc.SharedMemory(self.name)
self.mapfile = mmap.mmap(memory.fd, memory.size)
os.close(memory.fd)
return
def put(self, item):
"""Put item in shared memory.
"""
# TODO: Deal with the case where len(item) > size(self.mapfile)
# TODO: Guard this method with a named semaphore
self.mapfile.seek(0)
pickle.dump(item, self.mapfile, protocol=2)
return
def get(self):
"""Get a Python object from shared memory.
"""
# TODO: Deal with the case where len(item) > size(self.mapfile)
# TODO: Guard this method with a named semaphore
self.mapfile.seek(0)
return pickle.load(self.mapfile)
def __del__(self):
try:
self.mapfile.close()
memory = posix_ipc.SharedMemory(self.name)
memory.unlink()
except:
pass
return
For the Java side you want to create the same class, despite what I said in the comments JTux seems to provide the equivalent functionality and the API you need is in UPosixIPC class.
The code below is an outline of the sort of thing you need to implement. However, there are several things missing -- exception handling is the obvious one, also some flags (find them in UConstant), and you'll want to add in a semaphore to guard the put / get methods. However, this should set you on the right track. Remember that an mmap or memory-mapped file is a file-like interface to a segment of RAM. So, you can use its file descriptor as if it were the fd of a normal file.
import jtux.*;
class SHM {
private String name;
private int size;
private long semaphore;
private long mapfile; // File descriptor for mmap file
/* Lookup flags and perms in your system docs */
public SHM(String name, int size, boolean create, int flags, int perms) {
this.name = name;
this.size = size;
int shm;
if (create) {
flags = flags | UConstant.O_CREAT;
shm = UPosixIPC.shm_open(name, flags, UConstant.O_RDWR);
} else {
shm = UPosixIPC.shm_open(name, flags, UConstant.O_RDWR);
}
this.mapfile = UPosixIPC.mmap(..., this.size, ..., flags, shm, 0);
return;
}
public void put(String item) {
UFile.lseek(this.mapfile(this.mapfile, 0, 0));
UFile.write(item.getBytes(), this.mapfile);
return;
}
public String get() {
UFile.lseek(this.mapfile(this.mapfile, 0, 0));
byte[] buffer = new byte[this.size];
UFile.read(this.mapfile, buffer, buffer.length);
return new String(buffer);
}
public void finalize() {
UPosix.shm_unlink(this.name);
UPosix.munmap(this.mapfile, this.size);
}
}
Some thoughts
- The server is in Java, the client is written in Python.
An odd combination, but is there any reason one cannot call the other sending via stdin, stdout?
- Socket IPC is implemented below: it takes 50 cycles sending 200 bytes ! This has got to be too high. If I send 2 bytes in 5000 cycles, it takes a lot less time.
Any call to the OS is going to be relatively slow (latency wise). Using shared memory can by pass the kernel. If throughput is you issue, I have found you can reach 1-2 GB/s using sockets if latency isn't such an issue for you.
- Both processes run on one Linux machine.
Making shared memory ideal.
- In the real application about 10 calls to client's iFid.write() are made each cycle.
Not sure why this is the case. Why not build a single structure/buffer and write it once. I would use a direct buffer is NIO to minimise latency. Using character translation is pretty expensive, esp if you only need ASCII.
- This is done on a Linux system.
Should be easy to optimise.
I use shared memory via memory mapped files. This is because I need to record every message for auditing purposes. I get an average latency of around 180 ns round trip sustained for millions of messages, and about 490 ns in a real application.
One advantage of this approach is that if there are short delays, the reader can catch up very quickly with the writer. It also support re-start and replication easily.
This is only implemented in Java, but the principle is simple enough and I am sure it would work in python as well.
https://github.com/peter-lawrey/Java-Chronicle
Java IPC w/Sockets - Using Loopback Device - Stack Overflow
java - How to have 2 JVMs talk to one another - Stack Overflow
How to create IPC through sockets with a Java client and a Python server? - Stack Overflow
What is the best way for IPC in java? - Stack Overflow
Videos
Multiple options for IPC:
Socket-Based (Bare-Bones) Networking
- not necessarily hard, but:
- might be verbose for not much,
- might offer more surface for bugs, as you write more code.
- you could rely on existing frameworks, like Netty
RMI
- Technically, that's also network communication, but that's transparent for you.
Fully-fledged Message Passing Architectures
- usually built on either RMI or network communications as well, but with support for complicated conversations and workflows
- might be too heavy-weight for something simple
- frameworks like ActiveMQ or JBoss Messaging
Java Management Extensions (JMX)
- more meant for JVM management and monitoring, but could help to implement what you want if you mostly want to have one process query another for data, or send it some request for an action, if they aren't too complex
- also works over RMI (amongst other possible protocols)
- not so simple to wrap your head around at first, but actually rather simple to use
File-sharing / File-locking
- that's what you're doing right now
- it's doable, but comes with a lot of problems to handle
Signals
- You can simply send signals to your other project
- However, it's fairly limited and requires you to implement a translation layer (it is doable, though, but a rather crazy idea to toy with than anything serious.
Without more details, a bare-bone network-based IPC approach seems the best, as it's the:
- most extensible (in terms of adding new features and workflows to your
- most lightweight (in terms of memory footprint for your app)
- most simple (in terms of design)
- most educative (in terms of learning how to implement IPC). (as you mentioned "socket is hard" in a comment, and it really is not and should be something you work on)
That being said, based on your example (simply requesting the other process to do an action), JMX could also be good enough for you.
I've added a library on github called Mappedbus (http://github.com/caplogic/mappedbus) which enable two (or many more) Java processes/JVMs to communicate by exchanging messages. The library uses a memory mapped file and makes use of fetch-and-add and volatile read/writes to synchronize the different readers and writers. I've measured the throughput between two processes using this library to 40 million messages/s with an average latency of 25 ns for reading/writing a single message.
So, what's the recommended way to implement this? Custom protocol over raw socket [last resort solution], AMQP [seems nice on the C# side with data contracts, etc, but can it work w/o a broker/router], something else...?
Also, it has to work on Linux/osx.
For this, you're best off a file based FIFO queue. Or using Java Native Access/Java Native Interface to write to a NamedPipe or Shared Memory. If you go the JNA/JNI route, you could create a Named Event.
But there's probably no way to do what you want, with any amount of efficiency without going the JNA/JNI route.
You can use Java Management Extentions (JMX) to expose methods in a running process through a simple web interface.