目录
1.进程通信方式及对比
2. 通信方式编程
2.1 管道通信
2.2 命名管道通信
2.3 消息队列通信
2.4 信号量通信
2.5 共享内存
序号 | 通信方式 | 对比说明 |
1 | 管道(pipe) | 半双工通信,单向数据流,只能在父子进程间使用。 |
2 | 命名管道(named pipe) | 半双工通信,允许无亲缘关系进程通信 |
3 | 信号量(semophore) | 计数器,一种锁机制,用来控制多个进程对共享资源的访问 |
4 | 消息队列(message queue) | 消息链表存在内核并标识,克服信号传递信息少等问题 |
5 | 信号(signal) | 用于通知接收进程某个事件的发生 |
6 | 共享内存(shared memory) | 映射一块能被其他进程访问的内存,速度快,效率高 |
7 | 套接字(socket) | 不仅允许机器内部,也允许机器间的通信方式。 |
管道创建,其中fd[0] 为读端,fd[1]为写端
int pipe(int fd[2]);
管道使用,见下程序,若需要双向,则可以建立两个管道。
/*pipe_example.c*/
#include
#include
#include
#include
#include
void read_pipe(int fd);
void write_pipe(inf fd);
int main(void)
{
int fd[2];
pid_t pid;
int stat_1;
if (pipe(fd))
{
printf("pipe create failed \n");
exit(1);
}
pid = fork();
if ( pid == -1)
{
printf("fork error \n");
exit(1);
}
else if (pid == 0) /*chlid*/
{
close(fd[1]);/*关闭写*/
read_pipe(fd[0]);
exit(0);
}
else /*parent*/
{
close(fd[0]);
write_pipe(fd[1]);
wait(&stat_1);
exit(0);
}
exit(0);
}
void read_pipe(int fd)
{
char msg[100];
read(fd,msg,100);
printf("read pipe msg :%s",msg);
}
void write_pipe(inf fd)
{
char *msg = "my pipe \n";
write(fd,msg,strlen(msg)+1);
}
管道不足之处是,没有名字,只能在亲缘关系的进程间通信,命名管道则克服该限制,提供一个路径名与之关联,以FIFO的文件形式存储于文件系统中,该方式总是先进先出的原则工作。
int mknod(const char *path,mode_t mod,dev_t dev);
int mkfifo(const char *path,mode_t mod);
这里mod参数,用于声明其权限。
/*read_proc.c */
#include
#include
#include
#include
#include
#include
#define FIFO_NAME "fifo_ag"
#define BUF_SIZE (1024)
int main(void)
{
int fd;
char buf[BUF_SIZE];
umask(0);
fd = open(FIFI_NAME,O_RDONLY); /*只读方式*/
read(fd,buf,BUF_SIZE);
printf("read named pipe:%s \n",buf);
close(fd);
exit(0);
}
/*write_proc.c*/
#include
#include
#include
#include
#include
#include
#define FIFO_NAME "fifo_ag"
#define BUF_SIZE (1024)
int main(void)
{
int fd;
char buf[BUF_SIZE] = "write named pipe \n";
umask(0);
if (mkfifo(FIFO_NAME,S_FIFO | 0666) == -1)
{
perror("mkfifo error");
exit(1);
}
if ((fd = open(FIFO_NAME,O_WRONLY) == -1) /*只写方式*/
{
perror("open error");
exit(1);
}
write(fd,buf,strlen(buf)+1);
close(fd);
exit(0);
}
分别 gcc编译运行,即可得到两个进程传递的消息;若需要两个进程之间全双工通信,则可以建立两个管道。
消息队列是存放在内核中的消息链表,只有显示的删除消息队列,才会被真正删除。
消息队列缓存结构
struct msgbuf
{
long mtype;
char mtext[1];
};
消息队列创建,先要创建键值,每个消息队列有唯一的键值。
key_t ftok(const char* pathname,int proj_id);
消息队列根据键值来创建
int msgget(key_t key,int msgflg);
msgflg = IPC_CREATE,若不存在,则在内核创建,否则返回队列描述符
msgflg = IPC_EXCL,若队列已存在,返回-1 报错。
写消息队列
int msgsnd(int msqid,struct msgbuf *msgp,size_t msgsz,int magflg);
读消息队列
int msgrcv(int msqid,struct msgbuf *msgp,size_t msgse,long int msgtyp,int msgflg)
/*fifo_srv.c*/
#include
#include
#include
#include
#include
#include
#include
#include
#define BUF_SIZE (256)
#define PROJ_ID (32)
#define PATH_NAME "/tmp"
#define SRV_MSG (1)
#define CLT_MSG (2)
int main(void)
{
struct mymsgbuf
{
long msgtype;
char ctrlstr[BUF_SIZE];
};msgbuf;
int qid;
int msglen;
key_t msgkey;
if (msgkey = ftok(PATH_NAME,PROJ_ID)) == -1)
{
perror("ftok error");
exit(1);
}
if ((qid = msgget(msgkey,IPC_CREAT|0660)) == -1)
{
perror("msgget error\n");
exit(1);
}
while(1)
{
printf("server:");
fgets(msgbuf.ctrlstr,BUF_SIZE,stdin);
if (strncmp("exit",msgbuf.ctrlstr,4) == 0)
{
msgctl(qid,IPC_RMID,MULL);
break;
}
msgbuf.ctrlstr[strlen(msgbuff.ctrlstr)-1] = '\0';
msgbuf.msgtype = SRV_MSG;
if (msgsnd(qid,&msgbuf,strlen(msgbuf.ctrlstr)+1,0) == -1)
{
perror("server msgsnd error\n");
exit(1);
}
if (msgrcv(qid,&msgbuf,BUF_SIZE,CLT_MSG,0) == -1)
{
perror("server msgrcv error \n");
exit(1);
}
printf("client : %s \n",msgbuf.ctrlstr);
}
exit(0);
}
/*fifo_clt.c*/
#include
#include
#include
#include
#include
#include
#include
#include
#define BUF_SIZE (256)
#define PROJ_ID (32)
#define PATH_NAME "/tmp"
#define SRV_MSG (1)
#define CLT_MSG (2)
int main(void)
{
struct mymsgbuf
{
long msgtype;
char ctrlstr[BUF_SIZE];
}msgbuf;
int qid;
int msglen;
key_t msgkey;
if ((msgkey = ftok(PATH_NAME,PROJ_ID)) == -1)
{
perror("ftok error\n");
exit(1);
}
if ((qid = msgget(msgkey,IPC_CREAT|0660)) == -1)
{
perror("msgget error\n");
exit(1);
}
while(1)
{
if (msgrcv(qid,&msgbuf,BUF_SIZE,SRV_MSG,0) == -1)
{
perror("server msgrcv error\n");
exit(1);
}
printf("server : %s\n",msgbuf.ctrlstr);
printf("client:");
gets(msgbuf.ctrlstr,BUF_SIZE,stdin);
if (strncmp("exit",msgbuf.ctrlstr,4 == 0)
{
break;
}
msgbuf.ctrlstr[strlen(msgbuf.ctrlstr)-1] = '\0';
msgbuf.msgtype = CLT_MSG;
if (msgsnd(qid,&msgbuf,strlen(msgbuf.ctrlstr)_1,0) == -1)
{
perror("client msgsnd error\n");
exit(1);
}
}
exit(0);
}
先运行server端,再运行client端
信号量主要用于进程的同步问题,包括临界资源访问。
信号量创建,nsems表示要创建的信号的个数
int segget(key_t key,int nsems,int semflg);
当信号量的值大于0时,表示当前可用资源的数量,小于0,其绝对值表示等待使用该资源的进程个数。信号量的值仅能由PV操作来改变。
int semop(int semid,struct sembuf * sops,size_t nsops);
/*sem_srv.c*/
#include
#include
#include
#include
#define MAS_RESOURCE (5)
int main(void)
{
key_t key
int semid;
struct sembuf sbuf = {0,-1,IPC_NOWAIT};
union semun semopts;
if ((key = ftok(".",'s')) == -1)
{
perror("ftok error\n");
exit(1);
}
if ((semid = semget(key,i,IPC_CREAT|0666)) == -1)
{
perror("semget error\n");
exit(1);
}
semopts.val = MAX_RESOURCE;
if (semctl(semid,0,SETVAL,semopts) == -1)
{
perror("semctl error\n");
exit(1);
}
while(1)
{
if (semop(semid,&buf,1) == -1)
{
perror("semop error\n");
exit(1);
}
sleep(3);
}
exit(0);
}
/*sem_clt.c*/
#include
#include
#include
#include
int main(void)
{
key_t key;
int semid,semval;
union semun semopts;
if ((key = ftok(".",'s')) == -1)
{
perror("ftok error\n");
exit(1);
}
if ((semid = semget(key,1,IPC_CREAT|0666)) == -1)
{
perror("semget error\n");
exit(1);
}
while(1)
{
if ((semval = semctl(semid,0,GETVAL,0)) == -1)
{
perror("semctl error\n");
exit(1);
}
if (semval > 0)
{
printf("%d resources can be used \n",semval);
}
else
{
printf("no resources \n");
break;
}
sleep(3);
}
exit(0);
}
共享内存是分配一块能被其他进程访问的内存,维护的结构体如下
struct shmid_ds
{
struct ipc_perm shm_perm; /*
共享内存的操作--创建
int shmget(key_t key,size_t size,int shmflg);
共享内存的操作--操作,其中shmflg为权限标志
void* shmat(int shmid,const void * shmaddr,int shmflg);
共享内存的操作--结束操作
int shmdt(const void *shmaddr);
共享内存的操作--控制操作 (IPC_RMID 删除共享内存区,IPC_SET 设置,IPC_STAT 读取状态)
int shmctl(int shmid,int cmd,struct shmid_ds *buf);
/*shm_opt.c*/
#ifndef __SHM_OPT__
#define __SHM_OPT__
#include
#include
#include
#include
#include
#include
#include
#include
#define SHM_SIZE (1024)
union semun
{
int val;
struct semid_ds *buf;
unsigned short *array;
};
int creat_sem(const char *pathname,int proj_id,int members,int init_var);
int open_sem(const char *pathname,int proj_id);
int sem_p(int semid,int index);
int sem_v(int semid,int index);
int sem_del(int semid);
int sem_wait(int semid,int index);
int creat_shm(char *pathname,int proj_id,size_t size);
#endif
/*shm_opt.c*/
#include "shm_opt.h"
int creat_sem(const char *pathname,int proj_id,int members,int init_var)
{
key_t msgkey;
int index ,sid;
union senun semopts;
if ( msgkey = ftok(pathname,proj_id)) == -1)
{
perror("ftok error\n");
return -1;
}
if ((sid = semget(msgkey,members,IPC_CREAT|0666)) == -1)
{
perror("semget failed \n");
return -1;
}
semopts.val = init_var;
for (index = 0;index < members;index++)
{
semctl(sid,index,SETVAL,semopts);
}
return sid;
}
int open_sem(const char *pathname,int proj_id)
{
key_t key;
int sid;
if ((key = ftok(pathname,proj_id)) == -1)
{
perror("ftok \n");
return -1;
}
if ((sid = semget(key,0,IPC_CREAT|0666)) == -1)
{
perror("semget \n");
return -1;
}
return sid;
}
int sem_p(int semid,int index)
{
struct sembuf buf = {0,-1,IPC_NOWAIT};
if (index < 0)
{
perror("index < 0");
return -1;
}
buf.sem_num = index;
if (semop(semid,&buf,1) == -1)
{
perror("semop \n");
return -1;
}
return 0;
}
int sem_v(int semid,int index)
{
struct sembuf buf = {0 ,1,IPC_NOWAIT};
if (index < 0)
{
perror("index < 0 \n");
return -1;
}
buf.sem_num = index;
if (semop(semid,&buf,1) == -1)
{
perror("semop \n");
return -1;
}
return 0;
}
int sem_del(int semid)
{
return semctl(semid,0,IPC_RMID);
}
int sem_wait(int semid,int index)
{
while(semctl(semid,index,GETVAL,0) == 0)
{
sleep(1);
}
return 1;
}
int creat_shm(char *pathname,int proj_id,size_t size)
{
key_t key;
int sid;
if ((key = ftok(pathname,proj_id)) == -1)
{
perror("ftok \n");
return -1;
}
if ((sid = shmget(key,size,IPC_CREAT|0666)) == -1)
{
perror("shmget error\n");
return -1;
}
}
/*shm_wrt.c*/
#include "shm_opt.h"
int main(void)
{
int semid,shmid;
char *shmaddr;
char write_str[SHM_SIZE];
if ((shmid = creat_shm(".",'m',SHM_SIZE)) == -1)
{
exit(1);
}
if ((shmaddr = shmat(shmid,(char*)0,0) == (char*) -1)
{
perror("shmat error\n");
exit(1);
}
if ((semid == creat_sem(".",'s',1,1)) == -1)
{
exit(1);
}
while(1)
{
sem_wait(semid,0);
sem_p(semid,0);
printf("write:");
fgets(write_str,1024,stdin);
int len = strlen(write_str) - 1;
write_str[len] = '\0';
strcpy(shmaddr,write_str);
sleep(10);
sem_v(semid,0);
sleep(10);
}
exit(0);
}
/*shm_read.c*/
#include "shm_opt.h"
int main(void)
{
int semid,shmid;
char *shmaddr;
if ((shmid = creat_shm(".",'m',SHM_SIZE)) == -1)
{
exit(1);
}
if ((shmaddr = shmat(shmid,(char*)0,0)) == (char*)-1)
{
perror("shmat error\n");
exit(1);
}
if ((semid = sem_open(".",'s')) == -1)
{
exit(1);
}
while(1)
{
printf("read:");
sem_wait(semid,0);
printf("%s \n",shmaddr);
sleep(10);
sem_v(semid,0);
sleep(10);
}
exit(0);
}