Seven IPC communication mechanisms

Article directory

1.pipe

A pipeline allows one process to communicate with another process that has a common ancestor with it, that is, it can only be used to communicate between processes that have a kinship. Sample program:

#include <unistd.h>
#include <string.h>
#include <stdio.h>
int main(){
	int fd[2];
	int res = pipe(fd);
	if(res==-1)
		perror("pipe error");
	pid_t pid = fork();
	if(pid<0){
		perror("fork error");
	}else if(pid==0){
		close(fd[1]);
		char buf[BUFSIZ];
		ssize_t n = read(fd[0],buf,sizeof(buf));
		printf("read %ld bytes,%s\n",n,buf);
	}else{
		close(fd[0]);
		char buf[BUFSIZ];
		sprintf(buf,"Hello world!");
		ssize_t n = write(fd[1],buf,strlen(buf));
		printf("send %ld bytes,process %d\n",n,getpid());
	}
	return 0;
}

2.fifo: named pipe

Similar to pipeline, but it can be used for communication between any two processes. Named pipeline has corresponding file name in file system. The named pipe is created by the command mkfifo or the system call mkfifo. For example:

#include <unistd.h>
#include <string.h>
#include <stdio.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#define fifo "/tmp/fifo"
int main(){
	unlink(fifo);
	int res = mkfifo(fifo,0777);
	if(res==-1)
		perror("mkfifo error");
	pid_t pid = fork();
	if(pid<0){
		perror("fork error");
	}else if(pid==0){
		int rfd = open(fifo,O_RDONLY);
		char buf[BUFSIZ];
		ssize_t n = read(rfd,buf,sizeof(buf));
		printf("read %ld bytes,%s\n",n,buf);
	}else{
		int wfd = open(fifo,O_WRONLY);
		char buf[BUFSIZ];
		sprintf(buf,"Hello world!");
		ssize_t n = write(wfd,buf,strlen(buf));
		printf("send %ld bytes,process %d\n",n,getpid());
	}
	return 0;
}

3.signal: signal

Signal is a relatively complex communication mode, which is used to inform the receiving process that something has happened. In addition to interprocess communication, the process can also send signals to the process itself. Linux supports not only the early signal semantic function signal of UNIX, but also the signal function signal with the semantics conforming to POSIX.1 standard. Here we need to master the difference between signal and signal action. Signal directly specifies the callback function when the signal occurs. The latter can also set the signal mask set through parameters, and can clear and increase the signal to be shielded through the function signmptyset / sigaddset, etc
signal:

int main(){
	signal(SIGINT,SIG_IGN);
	while(1);
	return 0;
}

signaction:

int main(){
	struct sigaction act;
	act.sa_handler = SIG_IGN;
	sigemptyset(&act.sa_mask);
	sigaddset(&act.sa_mask,SIGTSTP);//SIGQUIT is generated for ^ z
	act.sa_flags = 0;
	sigaction(SIGINT,&act,0);//Act.sa-mask only indicates temporary blocking
	while(1);
	return 0;
}

4. shared memory

Memory mapping allows any multiple processes to communicate with each other. Each process using this mechanism implements it by mapping a shared memory to its own process address space. The related functions are as follows:

//Based on the file or directory name specified by pathname and the number specified by the proj? ID parameter, the ftok function generates a unique key value for the IPC object.
int  shmget(key_t key,size_t size,int shmflg)//Used to create shared memory
    /*key: The name of this shared memory segment is often obtained by using the ftok function, key_t ftok (const char * fname, int ID)
    *size: Size of shared memory
    *shmflg: It consists of nine permission flags, which are used the same way as the mode flag used when creating a file.
    *Return value: a non negative integer is returned successfully, that is, the flag code of the shared memory segment; a - 1 is returned in case of failure
    */
void* shmat (int shmid, const void* shmaddr, int shmflg)//Connect shared memory somewhere in the process address space
    /*shmid: Shared memory ID, obtained by shmget function
    *shmaddr: Specifies the address of the connection. Generally, NULL is selected by the kernel itself
    *shmflg: It may take SHM [rdonly] as read-only, others as read-write, and 0 as read-write
    *Return value: return a pointer to the first section of shared memory successfully; return - 1 in case of failure
    */
int shmdt(const void *shmaddr)//Detach the shared memory segment from the current process
    /*shmaddr: Pointer returned by shmat
    *Return value: success returns 0; failure returns - 1
    */
int shmctl (int shmid, int cmd, struct shmid_ds* buf)//Control shared memory
    /*shmid:Shared memory identifier returned by shmget
    *cmd:Action to be taken (three values are available)
 	*buf:Point to the data structure that holds the mode state and access permission of shared memory, generally NULL
    *Return value: success returns 0; failure returns - 1
    *cmd:IPC_STAT: Set the data in the shmid? DS structure to the current associated value of shared memory
    *    IPC_SET: When the process permission is sufficient, set the current associated value of shared memory to the value given in the shmid? DS data structure
    *    IPC_RMID: Delete shared memory
    */

Sample program:

#define PROJ_ID 0x7777
#define shmfile "/tmp/shfile"
int main()
{	
	key_t key = ftok(shmfile,PROJ_ID);
	int shmid = shmget(key,BUFSIZ,IPC_CREAT|IPC_EXCL|0777);//IPC? Create new shm
	char *des = shmat(shmid,NULL,0);
	sleep(2);
	int i=0;
	while(i<26)
	{
		i++;
		printf("read  bytes,%s\n",des);
		sleep(1);
	}
	shmdt(des);
	shmctl(shmid,IPC_RMID,0);
	return 0;
}

5. message queue

Message queue is the connection table of messages, including POSIX message pair and System V message queue. Processes with sufficient permissions can add messages to the queue, and processes with read permissions can read messages from the queue. Message queuing overcomes the disadvantages of less information, only unformatted byte stream and limited buffer size.

struct msg_buffer{  //Message structure
    long mtype;
    char mtext[1024];
};
  • Use the ftok function to obtain a key value of systemV, and then call the msgget function to obtain the message queue id. according to the key value
	key_t key = ftok("/tmp/message",1024);
	int messid = msgget(key,IPC_CREAT|0777);
  • Use ipcs -q to view the created message queues
---------Message queuing-----------
Message of bytes used for key msqid owner permission      
0x00000045 32769      centos     777        0            0 
  • Sending messages to message queues using the msgsnd function
int msgsnd(int msgid, const void *msg_ptr, size_t msg_sz, int msgflg);
/*msgid Is the message queue identifier returned by the msgget function
 *msg_ptr It is a pointer to the message to be sent, but the data structure of the message has certain requirements,
  The message structure pointed to by the pointer MSG ﹣ PTR must start with a long integer member variable and receive the function
  This member will be used to determine the type of message. As defined above, struct MSG buffer structure
 *msg_sz It is the length of the message pointed to by msg_ptr. Note that it is the length of the message, not the length of the whole structure,
  That is to say, MSG ﹣ SZ is the length of the member variable excluding the long integer message type.
 *msgflg Used to control what happens when the current message queue is full or when a queued message reaches a system wide limit, such as
  IPC_NOWAIT Indicates no blocking waiting
 *return : If the call succeeds, a copy of the message data will be put into the message queue and return 0. If the call fails, return - 1
 */
  • Use msgrcv function to read messages in message queue
int msgrcv(int msgid, void *msg_ptr, size_t msg_st, long int msgtype, int msgflg);
/*msgid, msg_ptr, msg_st Is the same as the function msgsnd().
 *msgtype A simple receive priority can be implemented. If msgtype is 0, the first message in the queue is obtained.
  If its value is greater than zero, the first information with the same message type is obtained. If it is less than zero, get the type
  The first message equal to or less than the absolute value of msgtype.
 *msgflg Is the same as the function msgsnd().
 *When the call is successful, the function returns the number of bytes put into the receive buffer, and the message is copied to the
  In the cache allocated by the user, then delete the corresponding message in the message queue. - 1 on failure.
 */
  • msgctl can be used to delete or operate message queues, or ipcrm can be used at the command line to delete message queues
int msgctl(int msgid, int command, struct msgid_ds *buf);
/*Grasp that when command equals IPC_RMID, it means to delete message queue, struct msgid_ds can be NULL.*/

6. semaphore

Semaphores are mainly used as synchronization means between processes and between different threads of the same process. Mainly to protect shared resources, it is often used together with shared memory when communicating between processes. The semaphore mechanism of systemV is mainly introduced below.

  • Semaphore defines P operation, which is used to request resource operation
  • Semaphore defines V operation, which is used to release resource operation
    The following is the semaphore function of systemV:

(1)semget function

int semget(key_t key, int num_sems, int sem_flags);
/*arg1:Same source as shmget,msgget
 *arg2:num_sems Specifies the number of semaphores required, whose value is almost always 1
 *arg3:sem_flags Is a set of flags. If you want to create a new semaphore when the semaphore does not exist, you can use the value IPC? Creat
  Do bit by bit or operation. When the IPC "creat flag is set, even if the given key is a key with an existing semaphore, it will not be generated
  Mistake. IPC | creat | IPC | excl can create a new and unique semaphore. If the semaphore already exists, an error will be returned.
 *retval:A corresponding signal identifier (non-zero) is returned successfully, and - 1 is returned in case of failure
 */

(2)semctl() function

int semctl(int sem_id, int sem_num, int command, ...);

If there is a fourth parameter, it is usually a union SEM structure, which is defined as follows:

union semun {
    int val;
    struct semid_ds *buf;
    unsigned short *arry;
};

The first two parameters are the same as in the previous function. command is usually one of the following two values:
SETVAL: used to initialize a semaphore to a known value, which is passed through union semun
The val member setting in is used to set the semaphore before it is used for the first time.
IPC? Rmid: used to delete a semaphore identifier that no longer needs to be used
(3)semop() function

int semop(int sem_id, struct sembuf *sem_opa, size_t num_sem_ops);

sem_id is the semaphore identifier returned by semget(). The sembuf structure is defined as follows:

struct sembuf{
    short sem_num; // It is 0 unless a set of semaphores is used
    short sem_op;  // The data that the semaphore needs to change in one operation is usually two numbers, one is - 1, that is, P (wait) operation,
                   // One is the + 1, or V (send signal) operation.
    short sem_flg; // Usually SEM ﹐ undo, which enables the operating system to track signals,
                   // And when the process terminates without releasing the semaphore, the operating system releases the semaphore
};

When SEM ﹣ flg is set to IPC ﹣ nowait, there is no resource and no wait, otherwise the wait will be suspended. SEM? OP > 0 indicates that the return resource adds it to the semaphore value. If there are processes sleeping waiting for this semaphore, wake them up.

7. Socket

It is a more general interprocess communication mechanism, which can be used for interprocess communication between different machines. I'm most familiar with it.

Published 23 original articles, won praise 6, visited 3791
Private letter follow

Tags: less socket Linux Unix

Posted on Mon, 10 Feb 2020 03:09:34 -0800 by sasori