新手上路系列9:进程间通信

1、两个程序之间传递数据的一种简单方法是使用popen与pclose。

FILE *popen(const char *command, const char *type); popen函数允许一个程序将另一个程序作为新进程来启动,并可以传递数据给它或者通过它接收数据。

command 字符串是要运行的程序名和相应的参数。type必须是"r"或"w"。"r"调用函数可以利用FILE*指针来读取被调程序的输入。"w"的话,调用程序可以向被调程序发送数据。

2、接下来,就是管道通了。什么是管道?管道是单向的,先进先出的,它把一个进程的输出和另一个进程的输入连接在一起一个进程(写进程)在管道尾部写入数据,

另一个进程(读进程)从管道的头部读出数据。管道的类型分为无名管道和命名管道两种:

1、)无名管道的创建由pipe() 函数实现。int pipe(int filedis[2]);当一个管道建立时,它会创建两个文件描述符:fd[0]用于读管道,fd[1]用于写管道。

无名管道用于父子进程间的通信,通常先创建一个管道,然后再通过fork() 函数创建一个子程序,该子程序会继承父进程所创建的管道描述符。另外,当使用一个管道

的某一端时,通常需要关闭另一端。当使用结束后,也要将使用端关闭(使用close)函数。

2、)命名管道的创建函数为:int mkfifo(const char *pathname, mode_t mode);通过命名管道,不相关的进程也能交换数据。而且一旦创建了一个FIFO,就可用open打开

它,一般的文件访问函数(close、read、write等)都可用 于FIFO(创建了一个管道文件)。

int main()
{
	int fd = open("/home/mkfifo", O_WRONLY);
	if (fd== -1)
	{
		perror ("mkfifo");
		return -1;
	}
	
	char buf[SIZE];
	fgets (buf, SIZE, stdin);
		
	write (fd, buf, strlen(buf));
		
	return 0;
}
这样就创建好了一个管道文件,可以在这之后使用函数获取管道中的值。但是管道中的值都是一次性的,当读取结束之后,管道里就空了,就不再可以读到数据。另外,这

里还要提到一点:如果管道所有的读端都被关闭,继续写数据系统默认的操作是使程序退出。


3、共享内存。共享内存是被多个进程共享的一部分物理内存。共享内存是进程间共享数据的一种最快的方法,一个进程向共享内存区域写入了数据,共享这个内存区域的

所有进程就可以立刻看到其中的内容。共享内存实现分为2个步骤:创建共享内存(shmget)与映射共享内存(shmat)。当一个进程不再需要共享内存时,需要把它从进程地

址空间中脱离(shmaddr)。最后就是删除共享内存了,可以使用shmctl 函数,在它的第二个参数 int command 中填入IPC_RMID 即可。此外,该函数第二个参数的其他2种

分别是IPC_STAT与IPC_SET,分别可以是:将共享内存中的值覆盖当前数据与设置共享内存的值为当前值(有足够权限的话)。

typedef struct _shm
{
	int flag;
	char msg[256];
}SHM;

int main()
{
	// 1、创建或者获取一个共享内存
	int shmid = shmget((key_t)1234, sizeof(SHM), 0666 | IPC_CREAT);
	if (shmid == -1)
	{
		perror ("shmget");
		return -1;
	}
	
	// 2、将共享内存映射到当前的进程空间
	SHM* pshm = (SHM*)shmat(shmid, NULL, 0);
	if(pshm == (SHM*)-1)
	{
		perror ("shmat");
		return -1;
	}
	
	strcpy (pshm->msg, "hello");
	
	// 解除共享内存映射,解除是指当前进程不能再使用共享内存
	shmdt(pshm);
	
	// 删除共享内存
	shmctl(shmid, IPC_RMID, NULL);
	

	return 0;
}
至于上面那个结构体是啥,以及这些函数的头文件是啥,可以像这样:man shmctl 来查看该函数的用户手册(当然是英文,不过还是能看懂一部分的)。


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

读走消息。首先,要获得一个消息队列的描述符,必须提供该消息队列的键值,可以使用ftok() 函数(但通常并不用,直接写一个键值就好)。接下里,创建:int msgget

 (key_t key, int msgflg);向消息队列中发送一条信息:int msgsnd(int msqid, struct msgbuf * msgp, int msgsz, int msgflg) ,其中比较复杂的是msgp:消息队列指针,指向存

放消息的结构。 还有就是int msgrcv(int msqid, struct msgbuf* msgp, int msgsz, long msgtp, int msgflg),功能是从msqid代表的消息队列中读取一个msdtyp类型的消息,

并把消息存储在msgp指向的msgbuf 结构中。在成功读取一条信息后,队列中的这条信息将被删除。最后,int msgctl(int msgid, int command, struct msgid_ds *buf);  同上面

的共享内存类似,也是第二个参数command 决定了队列的删除。

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

int main()
{
	// 创建消息队列
	int msgid = msgget((key_t)1234, 0666|IPC_CREAT);
	if (msgid == -1)
	{
		perror ("msgget");
		return -1;
	}
	
	struct msgbuf  msg;
	msg.mtype = 2;
	strcpy (msg.mtext, "hello");
	int ret = msgsnd(msgid, &msg, 256, IPC_NOWAIT);
	if (ret == -1)
	{
		perror ("nsgsnd");
		return -1;
	}
	
	return 0;
}
// 下面就可以通过另外一个程序来获取消息
	struct msgbuf  msg;
	int ret = msgrcv(msgid, &msg, 256, 2, IPC_NOWAIT);
	if (ret == -1)
	{
		perror ("nsgsnd");
		return -1;
	}
	
	printf ("%s\n", msg.mtext);






  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值