Linux的进程间通信

现在Linux使用的进程间通信方式包括:

1、管道(pipe)和有名管道(FIFO)

2、信号(signal)

3、消息队列

4、共享内存

5、信号量

6、套接字(socket)

管道通信

管道是单向的、先进先出的,它把一个进程的输出和另一个进程的输入连接在一起。 一个进程(写进程)在管道的尾部写入数据,另一个进程(读进程)从管道的头部读出数据。

管道提供了简单的流控制机制,进程试图读空管道时,进程将阻塞。同样,管道已经满时,进程再试图向管道写入数据,进程将阻塞

管道包括无名管道和有名管道两种,前者用于父进程和子进程间的通信,后者可用于运行于同一系统中的任意两个进程间的通信。    

无名管道创建:                 int pipe(int filedis[2]);    

当一个管道建立时,它会创建两个文件描述符:         filedis[0] 用于读管道、 filedis[1] 用于写管道

管道的创建:

#include <unistd.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
int main()
{
	int pipe_fd[2];
	if(pipe(pipe_fd)<0)
	{
		printf("pipe create error\n");
		return -1;
	}
	else
		printf("pipe create success\n");
	close(pipe_fd[0]);
	close(pipe_fd[1]);
}
重要注意点!:必须在系统调用fork( )前调用pipe( ),否则子进程将不会继承文件描述符

信号通信

常见的几种信号:

§ SIGHUP: 从终端上发出的结束信号

§ SIGINT: 来自键盘的中断信号(Ctrl-C)

§ SIGKILL:该信号结束接收信号的进程

§ SIGTERM:kill 命令发出的信号

§ SIGCHLD:标识子进程停止或结束的信号

§ SIGSTOP:来自键盘(Ctrl-Z)或调试程序的停止执行信号

发送信号的主要函数有 kill和raise。    

区别: Kill既可以向自身发送信号,也可以向其他进程发送信号。与kill函数不同的是,raise函数是向进程自身发送信号

   int kill(pid_t pid, int signo)
   int raise(int signo)

 共享内存        

共享内存是被多个进程共享的一部分物理内存.共享内存是进程间共享数据的一种最快的方法,一个进程向共享内存区域写入了数据,共享这个内存区域的所有进程就可以立刻看到其中的内容。

 

共享内存实现分为两个步骤:     

 一、创建共享内存,使用shmget函数          int shmget ( key_t key, int size, int shmflg )

二、映射共享内存,将这段创建的共享内存映射到具体的进程空间去,使用shmat函数:

 char * shmat ( int shmid, char *shmaddr, int flag)

关于内存共享的一段源代码 :

功能:两个子程序,若只打开A,则输出A的1-99,若打开A后,打开B,则A从计数到X(取决于打开的时间),A与B就共享内存,互相读取数据,输入总计为1-99。

/**************************************************************
  > File Name:send.c
  > Author: wow66lfy
  > Created Time: 2018年08月17日 星期五 11时53分27秒
 **************************************************************/

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

#define SHMKEY  1234
#define SHMSIZE 4096
#define SEMKEY  1234

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

void sem_p(int semid)
{
    int ret;
    struct sembuf sbuf;

    sbuf.sem_num = 0;
    sbuf.sem_op = -1;
    sbuf.sem_flg = SEM_UNDO;

    ret = semop(semid, &sbuf, 1);
    if(-1 == ret)
    {
        perror("semop");
        return;
    }
}

void sem_v(int semid)
{
    int ret;
    struct sembuf sbuf;

    sbuf.sem_num = 0;
    sbuf.sem_op = 1;
    sbuf.sem_flg = SEM_UNDO;

    ret = semop(semid, &sbuf, 1);
    if(-1 == ret)
    {
        perror("semop");
        return;
    }
}

int main()
{
    int shmid, semid, ret;
    void *shmaddr;
    int count = 0;

    shmid = shmget(SHMKEY, SHMSIZE, 0);
    if(-1 == shmid)
    {
        perror("shmget");
        exit(1);
    }

    semid = semget(SEMKEY, 1, 0);
    if(semid == -1)
    {
        perror("semget");
        exit(1);
    }

    shmaddr = shmat(shmid, NULL, 0);
    if(NULL == shmaddr)
    {
        perror("shmat");
        exit(1);
    }

    while(1)
    {
        sem_p(semid);
        count = *(int *)shmaddr;  //读取数据
        usleep(100000);
        if(count >= 100)
        {
            break;
        }

        printf("Process B : count = %d\n", count);

        count++;

        *(int *)shmaddr = count; //写回共享内存
        
        sem_v(semid);
    }
    shmdt(shmaddr);
    return 0;
}
/**************************************************************
  > File Name: recv.c
  > Author: wow66lfy
  > Created Time: 2018年08月17日 星期五 11时53分27秒
 **************************************************************/

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

#define SHMKEY  1234
#define SHMSIZE 4096
#define SEMKEY  1234

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

void sem_p(int semid)
{
    int ret;
    struct sembuf sbuf;

    sbuf.sem_num = 0;
    sbuf.sem_op = -1;
    sbuf.sem_flg = SEM_UNDO;

    ret = semop(semid, &sbuf, 1);
    if(-1 == ret)
    {
        perror("semop");
        return;
    }
}

void sem_v(int semid)
{
    int ret;
    struct sembuf sbuf;

    sbuf.sem_num = 0;
    sbuf.sem_op = 1;
    sbuf.sem_flg = SEM_UNDO;

    ret = semop(semid, &sbuf, 1);
    if(-1 == ret)
    {
        perror("semop");
        return;
    }
}

int main()
{
    int shmid, semid, ret;
    void *shmaddr;
    int count = 0;

    shmid = shmget(SHMKEY, SHMSIZE, 0);
    if(-1 == shmid)
    {
        perror("shmget");
        exit(1);
    }

    semid = semget(SEMKEY, 1, 0);
    if(semid == -1)
    {
        perror("semget");
        exit(1);
    }

    shmaddr = shmat(shmid, NULL, 0);
    if(NULL == shmaddr)
    {
        perror("shmat");
        exit(1);
    }

    while(1)
    {
        sem_p(semid);
        count = *(int *)shmaddr;  //读取数据
        usleep(100000);
        if(count >= 100)
        {
            break;
        }

        printf("Process B : count = %d\n", count);

        count++;

        *(int *)shmaddr = count; //写回共享内存
        
        sem_v(semid);
    }
    shmdt(shmaddr);
    return 0;
}

 单打开A:

Process A : count = 0
Process A : count = 1
Process A : count = 2
Process A : count = 3
Process A : count = 4
...(中间连续,以.代替了,否则太长了)
Process A : count = 95
Process A : count = 96
Process A : count = 97
Process A : count = 98
Process A : count = 99

打开A后打开B:

(两个终端打开,分别运行)
Process B : count = 5                                
Process B : count = 7
Process B : count = 9
Process B : count = 11
Process B : count = 13
(同)
Process B : count = 93
Process B : count = 95
Process B : count = 97
Process B : count = 99
                

Process A : count = 0
Process A : count = 1
Process A : count = 2
Process A : count = 3
Process A : count = 4
Process A : count = 6
...(同)
Process A : count = 94
Process A : count = 96
Process A : count = 98

消息队列

消息队列就是一个消息的链表.可以把消息看作一个记录,具有特定的格式.进程可以向中按照一定的规则添加新消息;另一些进程则可以从消息队列中读走消息

一个本地单人聊天源代码(手动滑稽!):

/**************************************************************
  > File Name: msgget_recv.c
  > Author: wow66lfy
  > Created Time: 2018年08月17日 星期五 11时53分27秒
 **************************************************************/

#include <stdio.h>
#include<sys/types.h>
#include<sys/ipc.h>
#include<sys/msg.h>
#include<stdlib.h>
#include<string.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>


#define MSGKEY 1234

struct msgbuf
{
    long mtype;
    char mtext[64];
};


int main()
{
    int ret;
	pid_t pid;
    struct msgbuf mbuf;
	
    int msgid = msgget(MSGKEY, 0);
    if(-1 == msgid )
    {
        perror("msgget");
        exit(1);
    }
	
	pid = fork();
	if(-1 == pid)
	{
		perror("fork");
		exit(1);
	}
	else if(0 == pid) //子程序发送
	{
		while(1)
		{
			memset(&mbuf, 0, sizeof(mbuf));

			mbuf.mtype = 2; //消息类型
			scanf("%s", mbuf.mtext);

			ret = msgsnd(msgid, &mbuf, sizeof(mbuf.mtext), 0);
			if(-1 == ret)
			{
				perror("msgsnd");
				exit(1);
			}
			if(!strcmp(mbuf.mtext, "bye"))
			{
				mbuf.mtype = 1;
				msgsnd(msgid, &mbuf, sizeof(mbuf.mtext), 0);
				break;
			}
		}
	}
	else        //父程序接收
	{
		while(1)
		{
			memset(&mbuf, 0, sizeof(mbuf));

			ret = msgrcv(msgid, &mbuf, sizeof(mbuf.mtext), 1, 0);

			if(-1 == ret)
			{
				perror("msgrcv");
				exit(1);
			}
			if(!strcmp(mbuf.mtext, "bye"))
			{
				kill(pid, 2);
				break;
			}
		printf("\t\t\t\t%s\n", mbuf.mtext);
		}
	}
    return 0;
}
/**************************************************************
  > File Name: msgget_send.c
  > Author: Lifengyu
  > Created Time: 2018年08月17日 星期五 11时53分27秒
 **************************************************************/

#include <stdio.h>
#include<sys/types.h>
#include<sys/ipc.h>
#include<sys/msg.h>
#include<stdlib.h>
#include<string.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>


#define MSGKEY 1234

struct msgbuf
{
    long mtype;
    char mtext[64];
};


int main()
{
    int ret;
	pid_t pid;
    struct msgbuf mbuf;
	
    int msgid = msgget(MSGKEY, IPC_CREAT | IPC_EXCL);
    if(-1 == msgid )
    {
        perror("msgget");
        exit(1);
    }
	
	pid = fork();
	if(-1 == pid)
	{
		perror("fork");
		exit(1);
	}
	else if(0 == pid) //子程序发送
	{
		while(1)
		{
			memset(&mbuf, 0, sizeof(mbuf));

			mbuf.mtype = 1;
			scanf("%s", mbuf.mtext);

			ret = msgsnd(msgid, &mbuf, sizeof(mbuf.mtext), 0);
			if(-1 == ret)
			{
				perror("msgsnd");
				exit(1);
			}
			if(!strcmp(mbuf.mtext, "bye"))
			{
				mbuf.mtype = 2;
				msgsnd(msgid, &mbuf, sizeof(mbuf.mtext), 0);
				break;
			}
		}
	}
	else        //父程序接收
	{
		while(1)
		{
			memset(&mbuf, 0, sizeof(mbuf));

			ret = msgrcv(msgid, &mbuf, sizeof(mbuf.mtext), 2, 0);

			if(-1 == ret)
			{
				perror("msgrcv");
				exit(1);
			}
			if(!strcmp(mbuf.mtext, "bye"))
			{
				kill(pid, 2);
				break;
			}
			printf("\t\t\t\t%s\n", mbuf.mtext);
		}
	}
	sleep(1);
    msgctl(msgid, IPC_RMID, NULL);
    return 0;
}

运行结果

猜你喜欢

转载自blog.csdn.net/wow66lfy/article/details/81835366