UNIX interprocess communication

UNIX interprocess communication mode

catalogue

1. Unknown pipeline

1.1example:

1.1. 1. Anonymous pipeline is a half duplex communication mode. When both parties need to communicate, two pipelines need to be established, which can only be used for communication between parent-child processes and brother processes.


1.1. 2. The anonymous pipeline alone constitutes an independent file system: the pipeline is a file for the processes at both ends of the pipeline, but it is not an ordinary file. It does not belong to a file system, but a self-supporting portal, which constitutes a file system alone and exists only in memory.


1.1. 3 data reading and writing: the content written by a process to the pipeline is read by the process at the other end of the pipeline. The content written is added to the end of the pipeline buffer every time, and the data is read from the head of the buffer every time.

1.2 implementation mode

#include<unistd.h>

1. Implementation function

int pipe(int fd[2])

//fp[0] read data
//fd[1] write data

1.3 examples:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
int main() {
  pid_t pid;
  int pfd[2];
  pipe(pfd);
  pid = fork();//Create child process
  if (pid < 0) {
    perror("open:");
    return -1;
  } else if (pid == 0) {
    char buffer[100] = "helloworld\n";
    while (1) {
      write(pfd[1], buffer, strlen(buffer));//Child processes for writing
      sleep(1);
    }
  } else {
    char buffer[100];
    while (1) {
      if (read(pfd[0], buffer, 100) > 0) {//Parent process for reading
        printf("recv from %s\n", buffer);
        sleep(1);
      } else {
        break;
      }
    }
  }
}

2. Famous pipeline

2.1. abstract

1. It is different from the pipeline in that it provides a path name associated with it and exists in the file system in the form of FIFO file.


2. Even processes that are not related to the creation process of FIFO can communicate with each other through FIFO as long as they can access the path (between processes that can access the path and the creation process of FIFO). Therefore, processes that are not related to FIFO can exchange data.


3.FIFO strictly follows the principle of first in first out (similar to queue). Reading pipes and FIFO always returns data from the beginning, and writing them adds data to the end. They do not support file location operations such as lseek().

2.2. Implementation method:

#include <sys/stat.h>

1. Implementation function

int mkfifo(const char * pathname, mode_t mode)

//Const char * pathname path to FIFO file
//mode_ Permissions of fifo files created by t mdoe

2.3. example:

//Fifo_Write

#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
int main() {
  if (mkfifo("/fifofile", 0666) == -1) {
    perror("faild:");
    return 0;
  }//Create fifo pipeline file.
  int fd;
  if ((fd = open("/fifofile", O_WRONLY)) < 0) {
    perror("open fifofile error");
    return -1;
  }//Open pipe file
  char buffer[100] = "hello\n";
  while (1) {
    write(fd, buffer, strlen(buffer));//Write data
    sleep(1);
  }
}


//Fifo_Read

#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <unistd.h>
int main() {
  int fd;
  if ((fd = open("/fifofile", O_RDONLY)) < 0) {
    perror("faild");
    return 0;
  }//Open pipe file
  char buffer[100];
  while (1) {
    read(fd, buffer, 100);//Read data
    printf("-->%s", buffer);
    sleep(1);
  }
}

3. Shared memory

3.1. abstract

Shared memory, as the name suggests, is the same memory space that can be accessed by two or more processes. The modification of this space by one process can be seen by other processes participating in communication. Obviously, in order to achieve this goal, we need to do two things: one is to delimit an area in memory as a shared area; The other is to map this region to the process spaces involved in communication. Shared memory is the fastest form of IPC. Once such memory is mapped to the address space of the processes sharing it, the data transfer between these processes no longer involves the kernel. In other words, processes no longer transfer each other's data by executing system calls into the kernel.

3.2. Implementation mode

#include <sys/shm.h>

1. Get shared memory

shmget(key_t key,size_t size,int shmflg)

//key_ id obtained by T key ftok function
//size_t size the shared memory size to get
//int shmflg flag bit

2. Map shared memory

shmat(int shmid,const void *shmaddr,int shmflg)

//Shared memory id number obtained by int shmid
//const void *shmaddr the address to be mapped. If it is set to NULL, the system will automatically map it
//int shmflg identification bit

3. Undo shared memory

shmdt(const void *shmaddr)

//const void *shmaddr mapped shared memory address

4. Specify shared memory control

shmct(int shmid,int cmd,struct shmid_ds *buf)

//Shared memory id number obtained by int shmid
//int cmd command to execute
//struct shmid_ds *buf

3.3. example

//ShareMemory read

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <unistd.h>
int main() {
  int shm_id;
  key_t key_id;
  if ((key_id = ftok(".", 100)) < 0) {
    perror("get share memory is failed");
    exit(0);
  }
  if ((shm_id = shmget(key_id, 512, IPC_CREAT | 0666)) < 0) {
    perror("get sharememory is faild!");
    exit(0);
  }//Get shareMemory id value
  char *addr;
  if ((addr = (char *)shmat(shm_id, NULL, 0666)) == NULL) {
    perror("mapping the share memory is faild!");
    exit(0);
  }//Map shared memory
  printf("-->%s", addr);
  shmdt((void *)addr);//Undo shared memory
  shmctl(key_id, IPC_RMID, NULL);//Delete shared memory
  sleep(1);
  return 0;
}


//ShareMemory write

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ipc.h>
#include <sys/shm.h>
int main() {
  int shm_id;
  key_t key_id;
  if ((key_id = ftok(".", 100)) < 0) {
    perror("get share memory is failed");
    exit(0);
  }
  if ((shm_id = shmget(key_id, 512, IPC_CREAT | 0666)) < 0) {
    perror("get sharememory is faild!");
    exit(0);
  }//Get shm_memory id value
  char *addr;
  if ((addr = (char *)shmat(shm_id, NULL, 0666)) == NULL) {
    perror("mapping the share memory is faild!");
    exit(0);
  }//Map shared memory
  strcpy(addr, "hello");
  shmdt(addr);//Unmap shared memory
  return 0;
}

4. Message queue

4.1. Summary:

The essence of message queue is a linked list of messages, which is maintained by the kernel; Each message in the message queue can be regarded as a record. The message includes a long integer type field and the data to be delivered. The message queue is identified by the message queue identifier (queue ID). Processes with read permission to the message queue can read messages from the queue, and processes with write permission to the message queue can add messages to it according to rules.

Compared with pipeline, the communication mode of message queue is more flexible: it provides formatted byte stream without additional data transmission format agreed by both sides of communication; The messages are set to different types and assigned different priorities. The newly added messages are always at the end of the queue, but the process receiving the messages can read the data in the middle of the queue. In addition, message queuing also reduces the coupling strength between reading and writing processes: if the process receiving the message does not receive the message, the process sending the message does not need to wait and can continue to send the message. Both sides of message reading and writing only need to pay attention to the implementation of their respective functions.

Similar to FIFO, message queue can realize the communication between unrelated processes and is independent of the processes of both communication parties. If the message queue in the kernel is not deleted, even if all processes using message queue have been terminated, the message queue still exists in the kernel until the kernel is restarted, the management command is executed or the system interface is called to delete the message queue, The message queue will really be destroyed.

The maximum number of message queues in the system and the maximum number of messages in the system are limited, which are defined by macro MSGMNI and macro MSGTOL respectively; The length of data blocks contained in each message of the message queue and the total length of data blocks contained in the queue are also limited, which are defined by the macros MSGMAX and MSGMNB respectively.

4.2. Implementation mode

#include <sys/msg.h>  

1. Message format

typedef struct {
    long int type;//Fixed format
    char msg[N];//variable
}

2. Get message queue

msgget(key_t key,int msgflg)

//key_ id obtained by T key ftok function
//int msgflg identification bit

3. Send message to message queue

msgsnd(int msgid,const void *msgp,size_t msgsz,int msgflg)

//id obtained by int msgid msgget function
//void *msgp message pointer
//size_ Tmessage length (excluding the type size in the message format)
//int msgflg flag bit

4. Get message from message queue

msgrcv(int msgid,const void *msgp,size_t msgsz,long type,int msgflg)

//id obtained by int msgid msgget function
//const void *msgp pointer to store messages
//size_t msgsz gets the length of the message
//long type gets the message type
//int msgflg flag bit

5. Control the specified message queue

msgctl(int msgid,int cmd,struct msgid_ds *buf);

//Message queue id number specified by int msgid
//int cmd requires instructions to be executed on the specified message queue
//struct msgid_ds *buf only if cmd is set to IPC_STAT or IPC_ Valid when set.

4.3. Instance

//Send message to message queue

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/msg.h>
#include <sys/types.h>
#include <unistd.h>
typedef struct {
  long type;
  char msg[64];
} MSG;
#define LEN (sizeof(MSG) - sizeof(long))
int main() {
  key_t id1;
  int msgid;
  id1 = ftok(".", 33);
  if (id1 == -1) {
    printf("get key id is fail!");
    exit(0);
  }
  msgid = msgget(id1, IPC_CREAT | 0666);
  if (msgid == -1) {
    printf("get the msgid is fail!");
    exit(0);
  }
  printf("msgid is --->%d\nshmid is --->%d\n", msgid, shmid);
  MSG MSG1;
  strcpy(MSG1.msg, "hello,world");
  MSG1.type = 1;
  msgsnd(msgid, &MSG1, LEN, 0);
}


//Receive from message queue
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/msg.h>
#include <sys/types.h>
typedef struct {
  long type;
  char msg[64];
} MSG;
#define LEN (sizeof(MSG) - sizeof(long))
int main() {
  key_t id1;
  int msgid;
  id1 = ftok(".", 33);
  if (id1 == -1) {
    printf("get key id is fail!");
    exit(0);
  }
  msgid = msgget(id1, IPC_CREAT | 0666);
  if (msgid == -1) {
    printf("get the msgid is fail!");
    exit(0);
  }
  MSG MSG1;
  msgrcv(msgid, &MSG1, LEN, -3, IPC_NOWAIT);
  printf("--->%s\n", MSG1.msg);
}

5. Signal lamp (System V signal lamp)

5.1} summary

It is used for process synchronization when multiple processes share some resources.

5.2 implementation mode

#include <sys/sem.h>

1. Turn on / create signal light

int semget(key_t key,int nsems,int semflg)

//key_ The key value obtained by the T key ftok function
//int nsems number of semaphores to be created
//int semflg flag bit

2. Designate signal lamp for control

int semctl(int semid,int semnum,int cmd)

//id value from int semid semget
//Semaphore index for int semnum operation
//int cmd instruction to execute

3. P/V operation

int semop(int semid, struct sembuf *sop,size_t nsops)

struct sembuf 
{
  short sem_num;//Beacon index
  short sem_op;//The operation performed - 1 is p operation and 1 is v operation
  short sem_flg;//Flag bit
}
//id from int semid semget function
//struct sembuf *sop 
//size_t nsops number of signal lamps to be operated.

5.3. Example:

#include <stdio.h>
#include <stdlib.h>
#include <sys/sem.h>
#include <sys/shm.h>
#include <sys/types.h>
#include <unistd.h>
#define sem_read 0
#define sem_write 1
union semun {
  int val;
};
void poperation(int index, int sem_id) {
  struct sembuf sem1;
  sem1.sem_num = index;
  sem1.sem_op = -1;
  sem1.sem_flg = 0;
  semop(sem_id, &sem1, 1);
}
void voperation(int index, int sem_id) {
  struct sembuf sem2;
  sem2.sem_num = index;
  sem2.sem_op = 1;
  sem2.sem_flg = 0;
  semop(sem_id, &sem2, 1);
}
int main() {
  key_t ipc_key;
  int shm_id, sem_id;
  ipc_key = ftok(".", 111);
  sem_id = semget(ipc_key, 2, IPC_CREAT | 0666); //Create two semaphores
  shm_id = shmget(ipc_key, 512, IPC_CREAT | 0666);
  if (shm_id < 0) {
    perror("create share memory:");
    exit(0);
  }
  if (sem_id < 0) {
    perror("create signal:");
    exit(0);
  }
  union semun val_wr, val_re;
  val_wr.val = 0;
  val_re.val = 1;
  semctl(shm_id, 0, SETVAL, val_wr);
  semctl(shm_id, 1, SETVAL, val_re); // Initialize two semaphores (read semaphore and write semaphore)
  pid_t sub_id;
  sub_id = fork();
  if (sub_id < 0) {
    perror("create sub process is failed");
    exit(0);
  } else if (sub_id == 0) {
    char *addr = (void *)shmat(shm_id, NULL, IPC_CREAT | 0666);
    while (1) {
      poperation(sem_read, sem_id);
      printf("---->%s", addr);
      voperation(sem_write, sem_id);
    }

  } else {
    char *addr = (void *)shmat(shm_id, NULL, IPC_CREAT | 0666);
    while (1) {
      poperation(sem_write, sem_id);
      fgets(addr, 10, stdin);
      voperation(sem_read, sem_id);
    }
  }
}

Keywords: Linux kernel

Added by sohdubom on Fri, 31 Dec 2021 10:15:42 +0200