您的位置:

深入了解Linux IPC

一、进程间通信概述

进程间通信,即Inter-Process Communication(IPC),是指不同进程之间进行信息交换和共享的机制。在Linux系统下,IPC有多种方法,包括管道、套接字、消息队列、共享内存等。

管道:是一种单向通信机制,只能在父子进程之间共享数据,并且只能用于有亲缘关系的进程间通信。使用C语言实现的例子:

#include <stdio.h>
#include <unistd.h>

#define BUFFER_SIZE 25
#define READ_END 0
#define WRITE_END 1

int main(void) {
    char write_msg[BUFFER_SIZE] = "Hello, world!";
    char read_msg[BUFFER_SIZE];
    int fd[2];
    pid_t pid;

    if (pipe(fd) == -1) {
        fprintf(stderr, "Pipe failed");
        return 1;
    }

    pid = fork();

    if (pid < 0) {
        fprintf(stderr, "Fork failed");
        return 1;
    }

    if (pid > 0) {
        close(fd[READ_END]);
        write(fd[WRITE_END], write_msg, strlen(write_msg)+1);
        close(fd[WRITE_END]);
    }
    else {
        close(fd[WRITE_END]);
        read(fd[READ_END], read_msg, BUFFER_SIZE);
        printf("Received message: %s\n", read_msg);
        close(fd[READ_END]);
    }

    return 0;
}

套接字:是一种双向通信机制,可以在不同的进程之间进行信息交换。可以分为面向连接(TCP)和无连接(UDP)套接字。使用Python实现的例子:

import socket

HOST = '127.0.0.1'
PORT = 12345

with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
    s.bind((HOST, PORT))
    s.listen(1)
    conn, addr = s.accept()
    with conn:
        print('Connected by', addr)
        while True:
            data = conn.recv(1024)
            if not data:
                break
            conn.sendall(data)

消息队列:是内核维护的一种队列,进程可以在队列中发送和接收消息。使用C语言实现的例子:

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

#define MSGSZ     128

typedef struct msgbuf {
    long mtype;
    char mtext[MSGSZ];
} message_buf;

int main() {
    int msqid;
    key_t key;
    message_buf rbuf;
    size_t buflen;

    key = ftok("msgq.txt", 'A');
    msqid = msgget(key, 0666 | IPC_CREAT);

    rbuf.mtype = 1;
    sprintf(rbuf.mtext, "Hello, world!");
    buflen = strlen(rbuf.mtext) + 1;

    msgsnd(msqid, &rbuf, buflen, IPC_NOWAIT);

    msgrcv(msqid, &rbuf, MSGSZ, 1, 0);
    
    printf("Received message: %s\n", rbuf.mtext);

    msgctl(msqid, IPC_RMID, NULL);

    return 0;
}

共享内存:是多个进程共享同一块物理内存的机制。使用C语言实现的例子:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ipc.h>
#include <sys/shm.h>

#define SHMSZ     27

int main() {
    int shmid;
    key_t key;
    char *shm, *s;

    key = ftok("shmfile", 'A');

    shmid = shmget(key, SHMSZ, 0666 | IPC_CREAT);

    shm = shmat(shmid, NULL, 0);

    s = shm;
    for (char c = 'a'; c <= 'z'; c++) {
        *s++ = c;
    }
    *s = '\0';

    while (*shm != '*') {
        sleep(1);
    }

    shmdt(shm);

    shmctl(shmid, IPC_RMID, NULL);

    return 0;
}

二、信号量机制

信号量(Semaphore)是一种保证多个进程之间互斥访问共享资源的机制。多个进程可以在信号量上进行等待和唤醒操作,并互相通知。在Linux系统下,信号量可以使用System V IPC 或 POSIX IPC实现。

System V IPC实现信号量,使用C语言实现的例子:

#include <stdio.h>
#include <stdlib.h>
#include <sys/ipc.h>
#include <sys/sem.h>

union semun {
    int val;
    struct semid_ds *buf;
    unsigned short *array;
    struct seminfo *__buf;
};

int main() {
    int sem_id;
    key_t key;
    struct sembuf sembuf;
    union semun arg;

    key = ftok("semfile", 'A');
    sem_id = semget(key, 1, 0666 | IPC_CREAT);

    arg.val = 1;
    semctl(sem_id, 0, SETVAL, arg);

    sembuf.sem_num = 0;
    sembuf.sem_op = -1;
    sembuf.sem_flg = SEM_UNDO;
    semop(sem_id, &sembuf, 1);

    printf("Semaphore locked!\n");

    sembuf.sem_op = 1;
    semop(sem_id, &sembuf, 1);

    printf("Semaphore unlocked!\n");

    semctl(sem_id, 0, IPC_RMID);

    return 0;
}

POSIX IPC也可以实现信号量机制,使用C语言实现的例子:

#include <stdio.h>
#include <stdlib.h>
#include <semaphore.h>

#define SEM_NAME "/mysem"

int main() {
    sem_t *sem;

    sem = sem_open(SEM_NAME, O_CREAT, 0666, 1);

    sem_wait(sem);
    printf("Semaphore locked!\n");
    sem_post(sem);
    printf("Semaphore unlocked!\n");

    sem_unlink(SEM_NAME);
    sem_close(sem);

    return 0;
}

三、共享内存机制

共享内存是一种高效的进程间通信机制,多个进程可以将同一块物理内存映射到自己的地址空间中,实现共享。在Linux系统下,共享内存可以使用System V IPC或 POSIX IPC实现。

System V IPC实现共享内存,使用C语言实现的例子:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ipc.h>
#include <sys/shm.h>

#define SHMSZ     27

int main() {
    int shmid;
    key_t key;
    char *shm, *s;

    key = ftok("shmfile", 'A');

    shmid = shmget(key, SHMSZ, 0666 | IPC_CREAT);

    shm = shmat(shmid, NULL, 0);

    s = shm;
    for (char c = 'a'; c <= 'z'; c++) {
        *s++ = c;
    }
    *s = '\0';

    while (*shm != '*') {
        sleep(1);
    }

    shmdt(shm);

    shmctl(shmid, IPC_RMID, NULL);

    return 0;
}

POSIX IPC也可以实现共享内存机制,使用C语言实现的例子:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <sys/mman.h>

#define SHMSZ     27

int main() {
    int fd;
    char *shm, *s;

    fd = shm_open("shmfile", O_CREAT | O_RDWR, 0666);
    ftruncate(fd, SHMSZ);

    shm = mmap(NULL, SHMSZ, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);

    s = shm;
    for (char c = 'a'; c <= 'z'; c++) {
        *s++ = c;
    }
    *s = '\0';

    while (*shm != '*') {
        sleep(1);
    }

    munmap(shm, SHMSZ);

    shm_unlink("shmfile");

    return 0;
}

四、消息队列机制

消息队列是一种专门用于进程间通信的机制,多个进程可以通过消息队列发送和接收消息。在Linux系统下,消息队列可以使用System V IPC或 POSIX IPC实现。

System V IPC实现消息队列,使用C语言实现的例子:

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

#define MSGSZ     128

typedef struct msgbuf {
    long mtype;
    char mtext[MSGSZ];
} message_buf;

int main() {
    int msqid;
    key_t key;
    message_buf rbuf;
    size_t buflen;

    key = ftok("msgq.txt", 'A');
    msqid = msgget(key, 0666 | IPC_CREAT);

    rbuf.mtype = 1;
    sprintf(rbuf.mtext, "Hello, world!");
    buflen = strlen(rbuf.mtext) + 1;

    msgsnd(msqid, &rbuf, buflen, IPC_NOWAIT);

    msgrcv(msqid, &rbuf, MSGSZ, 1, 0);
    
    printf("Received message: %s\n", rbuf.mtext);

    msgctl(msqid, IPC_RMID, NULL);

    return 0;
}

POSIX IPC也可以实现消息队列机制,使用C语言实现的例子:

#include <stdio.h>
#include <stdlib.h>
#include <mqueue.h>

#define QUEUE_NAME "/test_queue"
#define MSGSZ     128

int main() {
    mqd_t qd;
    char msgbuf[MSGSZ];
    struct mq_attr attr;

    attr.mq_flags = 0;
    attr.mq_maxmsg = 10;
    attr.mq_msgsize = MSGSZ;
    attr.mq_curmsgs = 0;

    qd = mq_open(QUEUE_NAME, O_CREAT | O_RDWR, 0666, &attr);

    mq_send(qd, "Hello, world!", 13, 0);

    mq_receive(qd, msgbuf, MSGSZ, NULL);

    printf("Received message: %s\n", msgbuf);

    mq_close(qd);
    mq_unlink(QUEUE_NAME);

    return 0;
}

五、总结

Linux IPC提供了多种机制用于进程间通信,包括管道、套接字、消息队列、共享内存和信号量。任何一种IPC机制都可以被应用于相应的场景中。