C 进程间通讯

先大概的总结一下,及基本的用法,其中每一个,展开都可以写一篇文章的

  • 匿名管道(Pipe)
  • 命名管道(Named pipe)
  • 消息队列 (Message Queues)
  • 信号 (Signal)
  • 信号量 (Semaphore)
  • 共享内存 (Shared Memory)
  • Socket

1.1匿名管道(Pipe)

//1.1匿名管道通讯
#include 
#include 
#include 
int main(int argc, char const *argv[])
{
    pid_t my_pid = getpid();
    char buffer[256];
    memset(buffer, 0, sizeof(buffer));
    int fildes[2];//fildes[0]接受数据,fildes[1]发送数据
    
    if (-1 == pipe(fildes)) {
        printf("创建管道失败\n");
        return 1;
    }
    int pid = fork();
    printf("fork result:%d\n",pid);

    if (pid == 0) { //子进程
        my_pid = getpid();//更新当前pid
        printf("子进程:%d: sleep 5s\n",my_pid);
        sleep(5);
        int nbyte = write(fildes[1], "你好呀,我是子进程", strlen("你好呀,我是子进程"));
        printf("子进程:%d:写了%d字节\n",my_pid, nbyte);
        close(fildes[1]);
    } else {
        my_pid = getpid();//更新当前pid
        read(fildes[0], buffer, sizeof(buffer));
        printf("父进程:%d:读了内容=>[%s]\n",my_pid, buffer);
        close(fildes[0]);
        printf("父进程:%d:sleep 5s\n",my_pid);
        sleep(5);
    }    
    
    return 0;
}

Res:

terence@k8s-master:/mydata/linux$ ./a.out
fork result:55440
fork result:0
子进程:55440
子进程:55440:写了27字节
父进程:55439:读了内容=>[你好呀,我是子进程]
父进程:55439

//与此同时另一个ssh窗口查看进程(因为代码中故意sleep了)
terence@k8s-master:/mydata/linux$ ps -ef | grep 'a.out'
terence   55439  97831  0 15:21 pts/0    00:00:00 ./a.out
terence   55440  55439  0 15:21 pts/0    00:00:00 ./a.out

其中ssh进程号是97831,测试进程a.out是55439,fork的子进程号为55440

1.2命名管道(Named pipe)

//1.2命名管道通讯
terence@k8s-master:/mydata/linux$ mkfifo named_pipe_1
terence@k8s-master:/mydata/linux$ ll
drwxrwxr-x  2 terence terence 4096 Jan  8 16:35 ./
drwxrwxrwx 20 root    root    4096 Jan  8 14:20 ../
prw-rw-r--  1 terence terence    0 Jan  8 16:35 named_pipe_1|
1.2.1 named_pipe_write.c
#include 
#include 
#include 
#include 
int main(int argc, char const *argv[])
{
    //O_RDWR   读写打开 不会阻塞
    //O_RDONLY 只读 会阻塞
    //O_WRONLY 只写 会阻塞
    char buf[255]="";
    int fd_write=open(argv[1],O_WRONLY);
    printf("fd_write=%d\n",fd_write);
    write(fd_write,"hello im writer",strlen("hello im writer"));
    printf("写入 hello im writer\n");
    return 0;
}
1.2.2 named_pipe_read.c
#include 
#include 
#include 
#include 
int main(int argc, char const *argv[])
{
    //O_RDWR   读写打开 不会阻塞
    //O_RDONLY 只读 会阻塞
    //O_WRONLY 只写 会阻塞
    char buf[255]="";
    int fd_read=open(argv[1],O_RDONLY);
    printf("fd_read=%d\n",fd_read);
    read(fd_read,buf,sizeof(buf));
    printf("read data:%s\n",buf);
    return 0;
}

Res:

terence@k8s-master:/mydata/linux$ ./write named_pipe_1  

---------------------------------------------------------------------------------------------------------------------------
阻塞......                                                            terence@k8s-master:/mydata/linux$ terence@k8s-master:/mydata/linux$./read named_pipe_1
---------------------------------------------------------------------------------------------------------------------------
fd_write=3
写入 hello im writer
---------------------------------------------------------------------------------------------------------------------------
                                                                      fd_read=3
                                                                      read data:hello im writer

1.3 消息队列 (Message Queues)

1.3.1 msg_send.c
#include 
#include 
#include 
#include 
#include 
#include 
#include 
//这个结构体可以自己定义,但必须要有一个消息类型type
typedef struct _msg
{
    long mtype;
    char mtext[50];
}MSG;
int main(int argc, char const *argv[])
{
    key_t key;
    int   msgqid;
    MSG   msg;

    key = ftok(".", 2021); // key 值
    // 创建消息队列
    msgqid = msgget(key, IPC_CREAT|0666);
    if(msgqid == -1)
    {
        perror("msgget");
        exit(-1);
    }

    msg.mtype = 100;    //消息类型
    strcpy(msg.mtext, "hello world!"); // 正文内容

    /* 添加消息
    msg_id:消息队列标识符
    &msg:消息结构体地址
    sizeof(msg)-sizeof(long):消息正文大小
    0:习惯用0
    */
    msgsnd(msgqid, &msg, sizeof(msg)-sizeof(long), 0);
    printf("send: %s\n", msg.mtext);

    return 0;
}
1.3.2 msg_read.c
#include 
#include 
#include 
#include 
#include 
#include 
#include 
//这个结构体可以自己定义,但必须要有一个消息类型type
typedef struct _msg
{
    long mtype;
    char mtext[50];
}MSG;
int main(int argc, char const *argv[])
{
    key_t key;
    int   msgqid;
    MSG   msg;
    
    key = ftok(".", 2021); // key 值
    // 创建消息队列
    msgqid = msgget(key, IPC_CREAT|0666);
    printf("msgqid=%d\n", msgqid);
    if(msgqid == -1)
    {
        perror("msgget");
        exit(-1);
    }

    memset(&msg, 0, sizeof(msg));
    /* 取出类型为 10 的消息
    msg_id:消息队列标识符
    &msg:消息结构体地址
    sizeof(msg)-sizeof(long):消息正文大小
    (long)10:消息的类型
    0:习惯用0
    */
    msgrcv(msgqid, &msg, 10000, 100, 0);
    printf("msg.mtext=%s\n", msg.mtext);

    // 把消息队列删除
    // IPC_RMID:删除标志位
    //msgctl(msgqid, IPC_RMID, NULL);
    return 0;
}

Res:

//msg_send
terence@k8s-master:/mydata/linux$ gcc -o msg_send msg_send.c
terence@k8s-master:/mydata/linux$ ./msg_send
send: hello world!

//查看队列
terence@k8s-master:/mydata/linux$ ipcs -q

------ Message Queues --------
key        msqid      owner      perms      used-bytes   messages    
0xe5013e9b 0          terence    666        56           1

//read
terence@k8s-master:/mydata/linux$ gcc -o msg_read msg_read.c
terence@k8s-master:/mydata/linux$ ./msg_read
msg.mtext=hello world!

1.3 信号 (Signal)

#include 
#include 
#include 
#include 
 
void SIGINT_handle(int sig_num)
{
    //Ctrl + C 捕获
    printf("reveice SIGINT signal %d \n", sig_num);
}
void SIGQUIT_handle(int sig_num)
{
    //Ctrl + \ 捕获
    printf("reveice SIGQUIT signal %d \n", sig_num);
}
 
int main(int argc, char argv[])
{
    int i = 0;
    signal(SIGINT, SIGINT_handle);
    signal(SIGQUIT, SIGQUIT_handle);
    while(i < 10){
        printf("wait signal\n");
        sleep(5);
        i++;
    }
    return 0;
}

Res:

terence@k8s-master:/mydata/linux$ gcc -o signal signal.c
terence@k8s-master:/mydata/linux$ ./signal
wait signal
^Creveice SIGINT signal 2 
wait signal
^\reveice SIGQUIT signal 3
---------------------------------------------------------------------------------------------------------------------------
                                                                    //也可以在别的窗口命令行kill发送信号
                                                                    terence@k8s-master:/mydata/linux$ ps -ef | grep signal
                                                                    terence@k8s-master:/mydata/linux$ kill -SIGINT 72553
---------------------------------------------------------------------------------------------------------------------------
wait signal
Killed

1.4 信号量 (Semaphore)

1.4.1 sem.c 操作信号量
#include 
#include 
#include 
#include 
#include 
#include 
// struct sembuf{
//     short sem_num; // 除非使用一组信号量,否则它为0
//     short sem_op;  // 信号量在一次操作中需要改变的数据,通常是两个数,一个是-1,即P(等待)操作,
//                    // 一个是+1,即V(发送信号)操作。
//     short sem_flg; // 通常为SEM_UNDO,使操作系统跟踪信号,
//                    // 并在进程没有释放该信号量而终止时,操作系统释放信号量
// };
union semun
{
 int             val;
 struct semid_ds *buf;
 unsigned short  *array;
 struct seminfo  *__buf; 
};
int main(int argc, char const *argv[])
{
    key_t key;
    int   semid;
    int   num;
    struct sembuf sem_b;
    union semun   sem_args;
    unsigned short array[1]={1};
    int op;

    sem_args.array = array;
    
    key = ftok(".", 2021); // key 值
    printf("key=%d\n", (int)key);
    printf("semid=%d\n", semid);

    
    // 创建信号量
    semid = semget(key, 1, IPC_CREAT|0666);

    semctl(semid, 0, SETALL, sem_args);//0代表对1个信号来量初始化,即有1个资源
    while(1){
        num = rand() % 100 + 1;

        if (num > 50)
        {
            op = 1;
        }else{
            op = -1;
        }
        sem_b.sem_num = 0;
        sem_b.sem_op = op;//P()
        sem_b.sem_flg = SEM_UNDO;
        semop(semid, &sem_b, 1);
        printf("set semval=%d\n", op);
        sleep(3);
    }
    return 0;
}
1.4.2 sem_client.c 读取信号量
#include 
#include 
#include 
#include 
#include 
int main(int argc, char const *argv[])
{
    key_t key;
    int   semid;
    int   semval;
    
    key = ftok(".", 2021); // key 值
    printf("key=%d\n", (int)key);
    printf("semid=%d\n", semid);
    // 创建信号量
    semid = semget(key, 1, IPC_CREAT|0666);

    while(1){
        semval = semctl(semid, 0, GETVAL, 0);
        printf("semval=%d\n", (int)semval);
        sleep(3);
    }
    return 0;
}

Res:

//set
terence@k8s-master:/mydata/linux$ gcc -o sem sem.c
terence@k8s-master:/mydata/linux$ ./sem
key=-452903269
semid=0
set semval=1
set semval=-1
set semval=1
set semval=-1
set semval=1
...

//查看
terence@k8s-master:~$ ipcs -s

------ Semaphore Arrays --------
key        semid      owner      perms      nsems     
0xe5013e9b 0          terence    666        1         

terence@k8s-master:~$

//get
terence@k8s-master:/mydata/linux$ gcc -o sem_client sem_client.c
terence@k8s-master:/mydata/linux$ ./sem_client
key=-452903269
semid=0
semval=1
semval=2
semval=3
semval=4
...

1.5 共享内存 (Shared Memory)

1.5.1 mem_write.c 写入共享内存
#include 
#include 
#include 
#include 
int main(int argc, char const *argv[])
{
    int   shmid;
    key_t key;
    //创建共享内存的key
    key = ftok(".", 2021); // key 值
    if (key == -1)
    {
        perror("ftok error");
    }
    // 创建1024字节的共享内存
    shmid = shmget(key, 1024, IPC_CREAT|0666);
    printf("shmid=%d\n", shmid);

    // 共享内存连接到本进程某个指针
    char *shmadd;
    shmadd = shmat(shmid, NULL, 0);

    char *msg;
    msg = "Hello World!";
    printf("set data to shared-memory :%s\n", msg);
    // Set data
    strcpy(shmadd, msg);
    // 分离
    shmdt(shmadd);
    return 0;
}
1.5.2 mem_read.c 读取共享内存
#include 
#include 
#include 
#include 
#include 
int main(int argc, char const *argv[])
{
    int   shmid;
    key_t key;
    //创建共享内存的key
    key = ftok(".", 2021); // key 值
    if (key == -1)
    {
        perror("ftok error");
    }
    // 创建|打开1024字节的共享内存
    shmid = shmget(key, 1024, IPC_CREAT|0666);
    printf("shmid=%d\n", shmid);

    // 共享内存连接到本进程某个指针
    char *shmadd;
    shmadd = shmat(shmid, NULL, 0);

    printf("read data from shared-memory :%s\n", shmadd);

    // 分离
    shmdt(shmadd);

    // 删除共享内存
    shmctl(shmid, IPC_RMID, NULL);
    return 0;
}

1.6 Socket

这里使用TCP示例

1.6.1 socket_server.c 服务端
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#define MYPORT  8887
#define QUEUE   20
#define BUFFER_SIZE 1024
int main(int argc, char const *argv[])
{
    //定义sockfd
    int server_socket = socket(AF_INET,SOCK_STREAM, 0);
    //定义sockaddr_in
    struct sockaddr_in server_sockaddr;
    memset(&server_sockaddr, 0, sizeof(server_sockaddr));  //每个字节都用0填充

    server_sockaddr.sin_family      = AF_INET;
    server_sockaddr.sin_port        = htons(MYPORT);
    server_sockaddr.sin_addr.s_addr = htonl(INADDR_ANY);

    //bind,成功返回0,出错返回-1
    if(bind(server_socket,(struct sockaddr *)&server_sockaddr,sizeof(server_sockaddr))==-1)
    {
        perror("bind");
        exit(1);
    }
    printf("blind...\n");

    //listen,成功返回0,出错返回-1
    if(listen(server_socket,QUEUE) == -1)
    {
        perror("listen");
        exit(1);
    }
    printf("listen...\n");

    //客户端套接字
    char   buffer[BUFFER_SIZE];
    struct sockaddr_in client_addr;
    socklen_t length = sizeof(client_addr);
 
    int conn;
    //成功返回非负描述字,出错返回-1
    conn = accept(server_socket, (struct sockaddr*)&client_addr, &length);
    if (conn == -1)
    {
        printf("accept error....\n");
        close(server_socket);
        exit(1);
    }
    printf("read socket=%d\n",conn);
    memset(buffer,0,sizeof(buffer));
    int len = read(conn, buffer, sizeof(buffer));
    printf("read data from %d:%s \n", conn, buffer);
    memset(buffer,0,sizeof(buffer));
    strcpy(buffer, "我收到啦!");
    write(conn, buffer, sizeof(buffer));
    printf("send data to %d:%s \n", conn,buffer);
    printf("close....\n");
    close(conn);
    close(server_socket);
    return 0;
}
1.6.2 socket_client.c 服务端
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
 
#define MYPORT  8887
#define BUFFER_SIZE 1024
 
int main()
{
    ///定义sockfd
    int sock_cli = socket(AF_INET,SOCK_STREAM, 0);
 
    ///定义sockaddr_in
    struct sockaddr_in servaddr;
    memset(&servaddr, 0, sizeof(servaddr));
    servaddr.sin_family = AF_INET;
    servaddr.sin_port = htons(MYPORT);  ///服务器端口
    servaddr.sin_addr.s_addr = inet_addr("127.0.0.1");  ///服务器ip
 
    ///连接服务器,成功返回0,错误返回-1
    if (connect(sock_cli, (struct sockaddr *)&servaddr, sizeof(servaddr)) < 0)
    {
        perror("connect");
        exit(1);
    }
    printf("connected!\n");
    char sendbuf[BUFFER_SIZE];
    char recvbuf[BUFFER_SIZE];

    memset(sendbuf , 0,  sizeof(sendbuf));
    strcpy(sendbuf, "你好啊,我是client!");
    write(sock_cli, sendbuf, strlen(sendbuf)); ///发送
    printf("send data %s \n", sendbuf);

    memset(recvbuf , 0,  sizeof(recvbuf));
    read(sock_cli, recvbuf, sizeof(recvbuf)); ///接收
    printf("get data %s \n", recvbuf);
    printf("close....\n");
    close(sock_cli);
    return 0;
}

Res:

//server
terence@k8s-master:/mydata/linux$ gcc -o socket_server socket_server.c
terence@k8s-master:/mydata/linux$ ./socket_server
blind...
listen...
read socket=4
read data from 4:你好啊,我是client! 
send data to 4:我收到啦! 
close....

//client
terence@k8s-master:/mydata/linux$ gcc -o socket_client socket_client.c
terence@k8s-master:/mydata/linux$ ./socket_client
connected!
send data 你好啊,我是client! 
get data 我收到啦! 
close....~~~~

你可能感兴趣的:(c,进程间通信)