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);