Interprocess Communication (Linux) (C)

Unnamed pipe

Create:
int pipe(int fd[2]);
Function: Create and process an unnamed pipe in the kernel, and generate two file descriptors (fd[0] for reading, fd[1] for writing)
Return value: 0 for success, -1 for failure
fd: the resulting file descriptor

Read: the read data will disappear
When the write terminal exists: read data will return the number of bytes actually read, if there is no data, read will block and wait
When the write end does not exist: if the data is read, it will return the actual number of bytes read, if there is no data, read will return 0

Write:
When the read end exists: write data normally, if the pipe space is larger than the size of the data to be written. Then you can write all the data; if the size of the pipe is smaller than the read data, only part of it will be written and blocked, and then written after the data is read
When the read end does not exist: writing will cause the pipe to burst (SIGPIPE) and the program will end directly

Famous pipeline

#include <sys/types.h>
#include <sys/stat.h>
int mkfifo(const char *pathname, mode_t mode);
Function: Create a FIFO file that exists in the file system, and its opening method is the same as opening a normal file
Return value: 0 for success, non-0 for failure (you can use errno to judge the error message)

Signal communication

#include <sys/types.h>
#include <signal.h>
int kill(pid_t pid, int sig);
Function: The process calling kill can send a signal to any
Return value: 0 for success, -1 for failure
pid: the process ID to receive
sig: signal

#include <signal.h>
int raise(int sig);
Function: Send a signal to this process
Return value: 0 for success, -1 for failure
sig: signal

#include <unistd.h>
unsigned int alarm(unsigned int seconds);
Function: Start a timer, start timing, and end the program after counting
Return value: return 0, return the remaining time of the previous alarm clock
seconds: the number of seconds, if it is 0, it means cancel the alarm clock

#include <unistd.h>
int pause(void);
Function: Suspend the process, when there is a signal, the process continues to run
Return value: return a positive number on success, -1 on failure


#include <signal.h>
typedef void (*sighandler_t)(int);
sighandler_t signal(int signum, sighandler_t handler);
// function prototype
void (*signal(int signum, void (*fun)(int)))(int)
Function: Capture a specified signal and choose different processing methods
Return value: address of the signal handler function on success, failure
signum: a signal
handler: signal processing function

IPC object

#include <sys/types.h>
#include <sys/ipc.h>
key_t ftok(const char *pathname, int proj_id);
Function: Generate a key value, no conflict when creating IPC objects.
Return value: key value for success, -1 for failure
pathname: file path name
proj_id: any value
(The generation of key requires a combined operation of the inode node number and proj_id of a file)

Shared memory (shm) (efficient)

ipcs: view shared memory segment
ipcrm -m memory terminal id: delete this memory segment
Multiple processes can access the same memory space, and each process is an independent space, so shared memory can only be in the kernel.
The kernel will map this space to user space. A synchronized mutual exclusion mechanism is required.

#include <sys/ipc.h>
#include <sys/shm.h>
int shmget(key_t key, size_t size, int shmflg);
Function: Open or create a shared memory object
Return value: success id number, failure -1
key: unique identifier (the value of ftok, if you want to become a private object use IPC_PRIVATE or 0)
size: the size of the shared memory space to be created
shmflg: open permission

#include <sys/types.h>
#include <sys/shm.h>
void *shmat(int shmid, const void *shmaddr, int shmflg);
Function: Map the kernel space of shared memory to user space
Return value: success return address, failure (void*) -1
shmid: memory idhao
shmaddr: Specifies the address of user space (default NULL)
shmflg: read and write permission (access) 0 can read and write

int shmdt(const void *shmaddr);
Function: Unmap
Return value: 0 for success, -1 for failure
shmaddr: mapping address

#include <sys/ipc.h>
#include <sys/shm.h>
int shmctl(int shmid, int cmd, struct shmid_ds *buf);
Function: control operation of shared memory objects
Return value: 0 for success, -1 for failure
shmid: shared memory segment id
cmd: control operation
buf: get related information structure

struct shmid_ds
{
           struct ipc_perm shm_perm; /* Ownership and permissions */
           size_t shm_segsz; /* Size of segment (bytes) */
           time_t shm_atime; /* Last attach time */
           time_t shm_dtime; /* Last detach time */
          time_t shm_ctime; /* Last change time */
           pid_t shm_cpid; /* PID of creator */
           pid_t shm_lpid; /* PID of last shmat(2)/shmdt(2) */
           shmatt_t shm_nattch; /* No. of current attaches */
           ...
       };
struct ipc_perm
{
           key_t __key; /* Key supplied to shmget(2) */
           uid_t uid; /* Effective UID of owner */
           gid_t gid; /* Effective GID of owner */
           uid_t cuid; /* Effective UID of creator */
           gid_t cgid; /* Effective GID of creator */
           unsigned short mode; /* Permissions + SHM_DEST and SHM_LOCKED flags */
           unsigned short __seq; /* Sequence number */
       };

Message queue (msg)

Choose whether to receive messages according to the type, and there is also a space in the kernel to exchange information.
but no mapping is required

struct msgbuf //message structure
{
           long mtype; /* message type, must be > 0 */
           char mtext[1]; /* message data */
};


#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
int msgget(key_t key, int msgflg);
Function: Open or create a message queue object
Return value: success queue id, failure -1
key: unique identifier (the value of ftok, if you want to become a private object use IPC_PRIVATE or 0)
msgflg: open permission

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
Function: Send a certain type of message to the queue
Return value: 0 for success, -1 for failure
msqid: message queue id number
msgp: message structure
msgsz: message structure size
msgflg: IPC_NOWAIT returns without waiting for the function to complete (not blocking), 0 returns after the function is executed (blocking)

ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg);
Function: extract the message of interest from the message queue
Return value: 0 for success, -1 for failure
msqid: message queue id number
msgp: message structure
msgsz: message structure size
msgtyp: the type of message you care about
msgflg: IPC_NOWAIT returns without waiting for the function to complete (not blocking), 0 returns after the function is executed (blocking)

int msgctl(int msqid, int cmd, struct msqid_ds *buf);
Function: control operation of shared memory objects
Return value: 0 for success, -1 for failure
msqmid: shared memory segment id
cmd: control operation
buf: get related information structure

Semaphore set (sem) collection of semaphores

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
int semget(key_t key, int nsems, int semflg);
Function: create or open a semaphore collection object
Return value: success semaphore set id, failure -1
key: unique identifier (the value of ftok, if you want to become a private object use IPC_PRIVATE or 0)
nsems: number of semaphore types
semflg: open permission

int semctl(int semid, int semnum, int cmd, ...);
Function: control and operate the signal lamp set, set content, delete, etc.
Return value: 0 for success, -1 for failure
semid: semaphore set id
semnum: semaphore number (starting from 0)
cmd: control command STEVAL (set signal light value), GETVAL (get signal light value)

int semop(int semid, struct sembuf *sops, size_t nsops);
Function: Realize the application and release of signal lights
Return value: 0 for success, -1 for failure
semid: semaphore set id
sops:
struct sembuf
{
unsigned short sem_num; /* semaphore number */
       short sem_op; /* semaphore operation (1 to release resources, -1 to apply)*/
       short sem_flg; /* operation flags (0 blocking, IPC_NOWAIT not blocking) */
}
nsops: the number of semaphores operated (such semaphores, such resources)

Some code samples

//Unnamed pipe
#include <stdio.h>
#include <unistd.h>
int main(int argc, char *argv[])
{<!-- -->
    int fd[2];
    int ret = pipe(fd);
    if(ret<0)
    {<!-- -->
        perror("pipe");
        return -1;
    }
    printf("%d--->%d\
",fd[0],fd[1]);
    char buf[1];
    int count=0;
    while(1)
    {<!-- -->
        write(fd[1],buf,sizeof(buf));
        printf("?\
",count ++ );
    }
    return 0;
}
//famous pipe
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <fcntl.h>

int main(int argc, char *argv[])
{<!-- -->
    int ret = mkfifo("./Newfifo",0777);
    if(ret<0)
    {<!-- -->
        if(errno!=EEXIST)
        {<!-- -->
            return -1;
        }
    }
    int fd = open("./Newfifo",O_RDWR);
    char buf[64];
    while(1)
    {<!-- -->
        read(fd,buf,sizeof(buf));
        printf("%s",buf);
        memset(buf,0,sizeof(buf));
    }
    return 0;
}
//shared memory
#include <stdio.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <errno.h>
int main(int argc, char *argv[])
{<!-- -->
    key_t key = ftok(".",'a');



    int shmid = shmget(key,512,IPC_CREAT | 0666 |IPC_EXCL);
    if(shmid<0)
    {<!-- -->
        if(errno==EEXIST)
        {<!-- -->
            shmid = shmget(key,512,0666);
        }
        else
        {<!-- -->
            perror("shmget");
            return -1;
        }
    }
    printf("shmid=%d\
",shmid);



    char *shmaddr = (char*)shmat(shmid,NULL,0);
    /*if(shmaddr==-1)
    {
        perror("shmat");
        return -1;
    }*/
    printf("shmaddr=%p\
",shmaddr);
    fgets(shmaddr,64,stdin);
    printf("%s",shmaddr);



    int ret = shmdt(shmaddr);
    if(ret==-1)
    {<!-- -->
        perror("shmdt");
        return -1;
    }



    struct shmid_ds buf;
    int ret01 = shmctl(shmid,IPC_STAT, &buf);
    if(ret01==-1)
    {<!-- -->
        perror("shmctl01");
        return -1;
    }
    printf("shm_pid=%d\
",buf.shm_cpid);
    int ret02 = shmctl(shmid,IPC_RMID,NULL);
    if(ret02==-1)
    {<!-- -->
        perror("shmctl02");
        return -1;
    }
    return 0;
}
//message queue
#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <unistd.h>
#include <errno.h>
struct msgbuf
{<!-- -->
    long mtype;
    char buf[64];
};
int main(int argc, char *argv[])
{<!-- -->
    int key = ftok(".",96);
    int msgid = msgget(key,IPC_CREAT | 0666 | IPC_EXCL);
    if(msgid<0)
    {<!-- -->
        if(errno==EEXIST)
        {<!-- -->
            msgid = msgget(key,0666);
        }
    }

    pid_t pid = fork();
    if(pid<0)
    {<!-- -->
        perror("fork");
        goto DestroyMsg;
    }
    else if(pid==0)
    {<!-- -->
        while(1)
        {<!-- -->
            struct msgbuf msgbuf_copy100;
            msgrcv(msgid, & msgbuf_copy100, sizeof(msgbuf_copy100), 100,0);
            printf("child copy:%s\
",msgbuf_copy100.buf);
        }
    }
    else
    {<!-- -->
        struct msgbuf msgbuf100;
        msgbuf100.mtype=100;
        while(1)
        {<!-- -->
            fgets(msgbuf100.buf, sizeof(msgbuf100.buf), stdin);
            msgsnd(msgid, & msgbuf100, sizeof(msgbuf100), 0);
        }
    }

DestroyMsg:
    msgctl(msgid, IPC_RMID, NULL);
    return 0;
}
//semaphore set
#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <errno.h>
#include <unistd.h>
int semset(int semid, int *a, int n)
{<!-- -->
    for(int i=0;i<n;i++)
    {<!-- -->
        semctl(semid,a[i],SETVAL,a[i]);
    }
}
int sem_ops(int semid, int num, int op)
{<!-- -->
struct sembuf buf;
buf.sem_num = num;
buf.sem_op = op;
buf.sem_flg = 0;
int ret = semop(semid, &buf, 1);
if(ret < 0){<!-- -->
perror("semop");
return -1;
}
return 0;
}
int main(int argc, char *argv[])
{<!-- -->
    int key = ftok(".",'a');
    int semid = semget(key,2,IPC_CREAT | 0666 | IPC_EXCL);
    if(semi<0)
    {<!-- -->
        if(errno==EEXIST)
        {<!-- -->
            semid = semget(key,2,0666);
        }
        return -1;
    }

    int a[2]={<!-- -->0,1};
    semset(semid,a,2);
    pid_t pid = fork();
    if(pid<0)
    {<!-- -->
        perror("fork");
        return -1;
    }
    else if(pid==0)
    {<!-- -->
        while(1)
        {<!-- -->
            sem_ops(semid,0,-1);
            printf("Im child");
            sleep(1);
            sem_ops(semid,1,1);
        }
    }
    else
    {<!-- -->
        while(1)
        {<!-- -->
            sem_ops(semid,1,-1);
            printf("Im parent");
            sleep(1);
            sem_ops(semid,0,1);
        }
    }
    return 0;
}