|Linux| IPC methods introduce, comparison and examples

Threads can share resource with each other, but processes can’t.
Communicating to another processes should use IPC methods.
Common IPC methods in Linux are pipe, shared memory, signal, message queue and domain socket.

This article will introduce shared memory and message queue.
The most efficiency is shared memory (than domain socket).

Shared Memory

There two ways, shmget and mmap, but new POXIS supports mmap/shm_open. I suggest you to use newer one.

– find shared memory objects: ls -l /dev/shm
– open an object by shm_open()
– map the shared memory object to address space mmap()
– unmap mumap()
– close the object close()
– delete the object shm_unlink()

The example is from http://logan.tw/posts/2018/01/07/posix-shared-memory/

sender.c

#include "protocol.h"
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <unistd.h>

int main() {
  int fd = shm_open(NAME, O_CREAT | O_EXCL | O_RDWR, 0600);
  if (fd < 0) {
    perror("shm_open()");
    return EXIT_FAILURE;
  }

  ftruncate(fd, SIZE);

  int *data = (int *)mmap(0, SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
  printf("sender mapped address: %p\n", data);

  for (int i = 0; i < NUM; ++i) {
    data[i] = i;
  }

  munmap(data, SIZE);
  close(fd);
  return EXIT_SUCCESS;
}

receiver.c

#include "protocol.h"
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <unistd.h>

int main() {
  int fd = shm_open(NAME, O_RDONLY, 0666);
  if (fd < 0) {
    perror("shm_open()");
    return EXIT_FAILURE;
  }

  int *data = (int *)mmap(0, SIZE, PROT_READ, MAP_SHARED, fd, 0);
  printf("receiver mapped address: %p\n", data);

  for (int i = 0; i < NUM; ++i) {
    printf("%d\n", data[i]);
  }

  munmap(data, SIZE);
  close(fd);
  shm_unlink(NAME);
  return EXIT_SUCCESS;
}

protocol.h

#ifndef PROTOCOL_H
#define PROTOCOL_H

#define NAME "/shmem-example"
#define NUM 3
#define SIZE (NUM * sizeof(int))
#endif 


Compile:
$ gcc -o sender sender.c -lrt
$ gcc -o receiver receiver.c -lrt



Compare:
https://stackoverflow.com/questions/21311080/linux-shared-memory-shmget-vs-mmap

mmap:
http://neokentblog.blogspot.com/2014/10/ipc-shared-memory-example.html?m=1

shmget:
http://jimmychenhaha.blogspot.com/2012/10/ipcshare-memory.html?m=1



Message Queue

server <> client


server.c

#include <stdio.h>
#include <stdlib.h>
#include <sys/msg.h>

// create the unique key
#define MSG_FILE "/etc/passwd"

// message structure
struct msg_form {
	long mtype;
	char mtext[256];
};

int main(){
	int msqid;
	key_t key;
	struct msg_form msg;
	
	// get key
	if((key = ftok(MSG_FILE,'z')) < 0){
		perror("ftok error");
		exit(1);
	}

	// key
	printf("Message Queue - Server key is: %d.\n", key);

	// create
	if ((msqid = msgget(key, IPC_CREAT|0777)) == -1){
		perror("msgget error");
		exit(1);
	}

	printf("My msqid is: %d.\n", msqid);
	printf("My pid is: %d.\n", getpid());

	for(;;) {
                // get the type of 888
		msgrcv(msqid, &msg, 256, 888, 0);
		printf("Server: receive msg.mtext is: %s.\n", msg.mtext);
		printf("Server: receive msg.mtype is: %d.\n", msg.mtype);

		msg.mtype = 999;
		sprintf(msg.mtext, "hello, I'm server %d", getpid());
                //send the type 999
		msgsnd(msqid, &msg, sizeof(msg.mtext), 0);
	}
	return 0;
}

client.c

#include <stdio.h>
#include <stdlib.h>
#include <sys/msg.h>

// create the unique key
#define MSG_FILE "/etc/passwd"

// message structure
struct msg_form {
	long mtype;
	char mtext[256];
};

int main(){
	int msqid;
	key_t key;
	struct msg_form msg;

	// get key
	if ((key = ftok(MSG_FILE, 'z')) < 0) {
		perror("ftok error");
		exit(1);
	}

	printf("Message Queue - Client key is: %d.\n", key);

	// crease msg queue
	if ((msqid = msgget(key, IPC_CREAT|0777)) == -1) {
		perror("msgget error");
		exit(1);
	}

        printf("My msqid is: %d.\n", msqid);
	printf("My pid is: %d.\n", getpid());

	// add msg, which type is 888
	msg.mtype = 888;
	sprintf(msg.mtext, "hello, I'm client %d", getpid());
	msgsnd(msqid, &msg, sizeof(msg.mtext), 0);

	// get the type of 777
	msgrcv(msqid, &msg, 256, 999, 0);
	printf("Client: receive msg.mtext is: %s.\n", msg.mtext);
	printf("Client: receive msg.mtype is: %d.\n", msg.mtype);
	return 0;
}

Compile:
$ gcc -o server server.c -lrt
$ gcc -o client client.c -lrt

References:
yayaya6d msg queue
https://wirelessr.gitbooks.io/working-life/content/multicast_ipc.html
https://songlee24.github.io/2015/04/21/linux-IPC/