0
点赞
收藏
分享

微信扫一扫

Linux系统编程(三)--- 进程间通信

天涯学馆 2022-04-14 阅读 96
linux

1、理论介绍

1.1、进程间通信的概念

两个进程间实现数据的互相传输的通信,进程间通信简称IPC。

1.2、进程间通信的方式

1、管道,管道又可以分为命名管道(FIFO)和无名管道
2、消息队列
3、共享内存
4、信号
5、信号量

1.3、各个进程间通信的特点

(1) 无名管道
1、无名管道的通信是半双工的,数据只能够单方向流动,具有固定的读端和写端。
2、无名管道的通信仅仅局限于父子进程和兄弟进程之间。
3、无名管道可以理解为是一种特殊的文件,对它的操作可以使用普通的read、write操作,但不是普通的文件,不属于文件系统,仅仅存在于内存中。
(2) 命名管道
1、FIFO可以在无关的进程之间实现通信。
2、FIFO有路径名与之相对应,以一种特殊的文件形式存在于文件系统中。
3、FIFO也是半双工通信。
(3) 消息队列
1、消息队列是消息的链表,存放于Linux的内核中,每一个消息队列由一个标识符来标识。
2、消息队列独立于发送和接收进程,进程终止时,消息队列以及其内容不会删除。
3、消息队列可以随机查询消息,不一定要按照先进先出的方式读取,也可以按照消息类型来读取。
(4) 共享内存
1、共享内存是两个或者多个的进程共享一个给定的存储区。
2、因为多个进程可以同时对共享内存进行操作,所以需要进行同步。
3、共享内存通常会配合信号量来使用,信号量用来同步共享内存的访问。
(5) 信号
信号对于Linux而言,实际上是一种软中断,主要是用于实现一些异步通信的方式,当然,也可以通过信号来实现进程间的通信。
(6) 信号量
信号量主要用于实现进程间的互斥与同步,用于对临界资源的保护,当一个进程在访问临界资源时,另一个进程则不可以访问临界资源。必须要等待到当前进程访问完临界资源并且释放锁后,另一个进程才可以访问临界资源。

2、案例介绍

2.1、管道

(1) 无名管道

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

int main()
{
	int fd[2] = {0};
	char read_buf[128] = {0};
	char* write_data = "hello world\n";
	pid_t pid = 0;
	if (pipe(fd) == -1)
	{
		printf("create pipe fail\n");
	}
	pid = fork();
	if (pid > 0)
	{
		sleep(3);
		close(fd[0]);
		write(fd[1], write_data, strlen(write_data));
		printf("i am father process\n");
		wait(NULL);
	}
	else if (pid == 0)
	{
		printf("i am children process\n");
		close(fd[1]);
		read(fd[0], read_buf, sizeof(read_buf));
		printf("i read data : %s\n",read_buf);
		exit(0);
	}
	return 0;
}

(2) 命名管道
当open一个FIFO时,是否设置非阻塞标志的区别(O_NONBLOCK)。
若是没有指定O_NONBLOCK,只读open则会阻塞到某个进程为写而打开此FIFO,只写open则会阻塞到某个进程为读而打开此FIFO。
fifo_read.c

#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>

int main()
{
	int fd = 0;
	char* file_path = "./file1";
	char read_buf[100] = {0};
	if ((mkfifo(file_path, 0666) == -1) && errno == EEXIST)
	{
		printf("this file is exist\n");
	}
	
	fd = open(file_path, O_RDONLY);
	printf("open file success\n");
	while(1)
	{
		read(fd, read_buf, sizeof(read_buf));
		printf("read_buf : %s\n", read_buf);
	}
	close(fd);
	return 0;
}

fifo_write.c

#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <errno.h>
#include <fcntl.h>
#include <string.h>
#include <stdlib.h>

int main()
{
    int fd = 0;
	char* write_data = "i am write data\n";
    char* file_path = "./file1";
    fd = open(file_path, O_WRONLY);
	while(1)
	{
		write(fd, write_data, strlen(write_data));
		sleep(1);
	}
	close(fd);
    return 0;
}

2.2、消息队列

msg_client.c

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

typedef struct msgbuf
{
        long mtype;
        char mtext[128];
}msgbuf_t;

int main()
{
        key_t key = 0;
        int msg_id = 0;
        msgbuf_t msg_write_buf = {111, "i am zoudonghong"};
		msgbuf_t msg_recv_buf = {0};

        key = ftok(".", 11);
        msg_id = msgget(key, IPC_CREAT | 0777);
        if (msg_id == -1)
        {
                printf("get msg fail\n");
        }
        msgsnd(msg_id, &msg_write_buf, strlen(msg_write_buf.mtext), 0);
		msgrcv(msg_id, &msg_recv_buf, sizeof(msg_recv_buf.mtext),222,0);
		msgctl(msg_id, IPC_RMID, NULL);
		printf("i have recv:%s, type = %ld\n",msg_recv_buf.mtext, msg_recv_buf.mtype);
        return 0;
}

msg_server.c

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

typedef struct msgbuf 
{
	long mtype;
	char mtext[128];
}msgbuf_t;

int main()
{
	key_t key = 0;
	int msg_id = 0;
	msgbuf_t msg_read_buf = {0};
	msgbuf_t msg_ack_buf = {222, "i am fozu,thank you"};

	key = ftok(".", 11);
	msg_id = msgget(key, IPC_CREAT | 0777);
	if (msg_id == -1)
	{
		printf("get msg fail\n");
	}
	msgrcv(msg_id, &msg_read_buf, sizeof(msg_read_buf.mtext), 111, 0);
	printf("i recv buf : %s\n", msg_read_buf.mtext);
	
	msgsnd(msg_id, &msg_ack_buf, strlen(msg_ack_buf.mtext), 0);
	msgctl(msg_id, IPC_RMID, NULL);
	return 0;
}

2.3、共享内存

shm_read.c

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

int main()
{
	key_t key = 0;
	char* shm_addr = NULL;
	int shmid = 0;
	key = ftok(".", 1);
	shmid = shmget(key, 4 * 1024, 0);
	if (shmid == -1)
	{
		printf("get shm fail\n");
		exit(-1);
	}
	shm_addr = shmat(shmid, NULL, 0);
	
	printf("i read buf : %s\n", shm_addr);
	
	shmdt(shm_addr);
	return 0;
}

shm_write.c

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

int main()
{
	key_t key = 0;
	char* shm_addr = NULL;
	int shmid = 0;
	key = ftok(".", 1);
	shmid = shmget(key, 4 * 1024, IPC_CREAT | 0666);
	if (shmid == -1)
	{
		printf("get shm fail\n");
		exit(-1);
	}
	shm_addr = shmat(shmid, NULL, 0);
	strcpy(shm_addr, "i am zoudonghong");
	sleep(10);
	printf("shm get over\n");
	shmdt(shm_addr);
	
	shmctl(shmid, IPC_RMID, NULL);
	return 0;
}

2.4、信号

入门版的信号:
signal_recv.c

#include <stdio.h>
#include <signal.h>

typedef void (*sighandler_t)(int);

static void ldsMySignalHandler(int signal_num)
{
	printf("i get signal num = %d\n", signal_num);
}

int main()
{
	signal(SIGINT, ldsMySignalHandler);
	signal(SIGKILL, ldsMySignalHandler);
	signal(SIGUSR1, ldsMySignalHandler);
	while(1);
	return 0;
}

signal_send.c

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <signal.h>

int main(int argc, char** argv)
{
	if (argc != 3)
	{
		printf("you input arg num error\n");
		exit(-1);
	}
	pid_t pid = 0;
	int sig = 0;
	pid = atoi(argv[1]);
	sig = atoi(argv[2]);
	
	printf("pid = %d, sig = %d\n", pid, sig);
	kill(pid, sig);

	return 0;
}

高级版本:可以实现数据的交互
high_signal_send.c

#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>

int main(int argc, char** argv)
{
	pid_t pid = 0;
	int sig = 0;
	union sigval value;
	printf("my pid = %d\n", getpid());	
	if (argc != 3)
	{
		printf("you input arg error\n");
		exit(-1);
	}
	pid = atoi(argv[1]);
	sig = atoi(argv[2]);
	value.sival_int = 2000;
	sigqueue(pid, sig, value);
	return 0;
}

high_signal_recv.c

#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>

void ldsRecvSignalHandler(int sig_num, siginfo_t *info, void* context)
{
	printf("sig_num = %d\n", sig_num);
	if (context != NULL)
	{
		printf("i receive pid = %d, data = %d\n", info->si_pid,info->si_int);
		printf("data = %d\n", info->si_value.sival_int);
	}
}

int main()
{
	struct sigaction act;
	printf("my pid = %d\n", getpid());
	act.sa_sigaction = ldsRecvSignalHandler;
	act.sa_flags = SA_SIGINFO;	
	sigaction(SIGUSR1, &act, NULL);
	while(1);
	return 0;
}

2.5、信号量

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

union semun 
{
     int              val;    /* Value for SETVAL */
     struct semid_ds *buf;    /* Buffer for IPC_STAT, IPC_SET */
     unsigned short  *array;  /* Array for GETALL, SETALL */
     struct seminfo  *__buf;  /* Buffer for IPC_INFO
                                 (Linux-specific) */
};

//信号量的P操作
static void ldsPGetKey(int sem_id)
{
	struct sembuf sem_val;
	sem_val.sem_num = 0;
	sem_val.sem_op = -1;
	sem_val.sem_flg = SEM_UNDO;
	semop(sem_id, &sem_val, 1);
}

//信号量的V操作
static void ldsVPutBackKey(sem_id)
{
	struct sembuf sem_val;
        sem_val.sem_num = 0;
        sem_val.sem_op =  1;
        sem_val.sem_flg = SEM_UNDO;
        semop(sem_id, &sem_val, 1);
}

int main()
{
	key_t key = 0;
	pid_t pid = 0;
	int sem_id = 0;
	union semun sem_item = {0};
	key = ftok(".", 1);
	sem_id = semget(key, 1, IPC_CREAT | 0666);		//创建信号量集合
	sem_item.val = 0;								//初始信号量值设置为0						
	semctl(sem_id, 0, SETVAL, sem_item);			//给信号量集合赋予初值
	pid = fork();
	if (pid > 0)
	{
		ldsPGetKey(sem_id);
		printf("i am father process\n");
		ldsVPutBackKey(sem_id);
	}
	else if(pid == 0)
	{
		ldsVPutBackKey(sem_id);
		printf("i am child process\n");
	}
	else
	{
		printf("create process fail\n");
	}
	return 0;
}

举报

相关推荐

进程间通信(系统编程)

0 条评论