管道
又内核提供,单工,自同步机制。使用广泛。(管道必须凑齐读写双方才能够运行。)
匿名管道
/home/qt/c/linux_c/ipc/pipe
看不到管道的名称,适合有亲缘关系的进程通信。
pipe.c
int pipe(int fildes[2]);
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <sys/wait.h>
#include <sys/types.h>
#define BUFSIZE 1024
int main()
{
pid_t pid;
int ret;
int pd[2];
char buf[BUFSIZE];
int len;
ret = pipe(pd); // 0是读,1是写
if(ret<0)
{
perror("pipe()");
exit(1);
}
pid = fork();
if(pid == 0)
{
//child read
close(pd[1]);
puts("Child Begin");
len = read(pd[0],buf,BUFSIZE); //如果父进程不写,那么会阻塞等待
write(1,buf,len);
close(pd[0]);
puts("Child End");
exit(1);
puts("Exit");
}
else if(pid >0)
{
sleep(1);
// parent write
close(pd[0]);
write(pd[1],"Hello\n",6);
close(pd[1]);
// wait(NULL);
exit(1);
}
return 0;
}
player.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#define BUFSIZE 1024
int main()
{
pid_t pid;
int ret;
int pd[2];
char buf[BUFSIZE];
int len;
ret = pipe(pd); // 0是读,1是写
if(ret<0)
{
perror("pipe()");
exit(1);
}
pid = fork();
if(pid == 0)
{
//child read
close(pd[1]);
dup2(pd[0],0); //将管道重定向到标准输入。
close(pd[0]);
int fd = open("/dev/null",O_RDWR);
dup2(fd,1);//关闭文件描述符1,然后文件描述符1执行 /dev/null
dup2(fd,2);
execl("usr/bin/mpg123","mpg123","-",NULL);
perror("excel");
exit(0);
}
else if(pid >0)
{
close(pd[0]);
//父进程从网上收数据,在管道中写。
close(pd[1]);
wait(NULL);
exit(0);
}
return 0;
}
命名管道
mkfifo namedfifo可以创建一个命名管道,文件类型为P
可以看到管道的名称,适合非亲缘关系的进程通信。
mkfifo
int mkfifo(const char *pathname, mode_t mode);
XSI ->SysV
XSI(System Interface and Headers),代表一种Unix系统的标准 XSI IPC,依托标识符和键来实现的,如同管道靠文件描述符来实现一样。包含了三种通信机制:消息队列,信号量,共享内存。
ipcs命令:可以看到 消息队列,信号量数组,共享内存的信息。
key:ftok();拿到同一个key值。
key_t ftok(const char *pathname, int proj_id); //hash的原串+杂志。
xxxget xxxop xxxctl
xxx -> msg sem shm
消息队列
消息队列有缓存数据的能力,通过ulimit -a查看
主动端:先发包的一方。
被动端:先收包的一方。
/home/qt/c/linux_c/ipc/xsi/msg/basic
int msgget(key_t key, int msgflg);
int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp,
int msgflg);
int msgctl(int msqid, int cmd, struct msqid_ds *buf);
proto.h
#ifndef PROTO_H
#define PROTO_H
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#define KEYPATH "/etc/services"
#define KEYPROJ 'a'
#define NAMESIZE 1024
struct msg_st
{
long mtype;
char name[NAMESIZE];
int math;
int chinese;
};
#endif
snder.c
#include <stdlib.h>
#include <stdio.h>
#include "proto.h"
int main()
{
key_t key;
key = ftok(KEYPATH,KEYPROJ);
if(key <0)
{
perror("ftok()");
exit(1);
}
int msgid;
msgid = msgget(key,0);
if(msgid <0)
{
perror("msgget");
exit(1);
}
struct msg_st sbuf;
sbuf.mtype = 1;
sprintf(sbuf.name,"%s","hello msg");
sbuf.math = rand()%100;
sbuf.chinese = rand()%100;
int len;
len = msgsnd(msgid,&sbuf,sizeof(sbuf) - sizeof(long),0);
if(len <0)
{
perror("msgsnd()");
exit(1);
}
puts("OK!");
// msgctl();
return 0;
}
recv.c
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include "proto.h"
int main()
{
key_t key;
key = ftok(KEYPATH,KEYPROJ);
if(key <0)
{
perror("ftok()");
}
int msgid;
msgid = msgget(key,IPC_CREAT|0600 );
if(msgid<0)
{
perror("msgget");
}
struct msg_st rbuf;
int len;
while(1)
{
len = msgrcv(msgid,&rbuf,sizeof(rbuf)-sizeof(long),0,0 );
if(len <0)
{
perror("msgrcv");
}
printf("NAME = %s \n",rbuf.name);
printf("MATH = %d \n",rbuf.math);
printf("CHINESE = %d \n",rbuf.chinese);
}
msgctl(msgid,IPC_RMID,NULL);
return 0;
}
命令:ipcrm 删除上述程序中产生的消息队列。ipc -q (msqid号)
消息队列ftp协议
#ifndef PROTO_H
#define PROTO_H
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#define KEYPATH "/etc/services"
#define KEYPROJ 'a'
#define PATHSIZE 1024
#define DATASIZE 1024
enum
{
MSG_PATH =1,
MSG_DATA,
MSG_EOT
}
typedef struct msg_path_st
{
long mtype; //must be MSG_PATH
char path[PATHSIZE]; //ASCII带尾0的串
}msg_path_t;
typedef struct msg_data_st
{
long mtype;
char data[DATAMAX];
int datalen;
}msg_data_t;
typedef struct msg_eot_st
{
long mtype;
}msg_eot_t;
union msg_s2c_un
{
long mtype; //提取公因子。
msg_data_t datamsg;
msg_eot_t eotmsg;
};
#endif
#ifndef PROTO_H
#define PROTO_H
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#define KEYPATH "/etc/services"
#define KEYPROJ 'a'
#define PATHSIZE 1024
#define DATASIZE 1024
enum
{
MSG_PATH =1,
MSG_DATA,
MSG_EOT
}
typedef struct msg_path_st
{
long mtype; //must be MSG_PATH
char path[PATHSIZE]; //ASCII带尾0的串
}msg_path_t;
typedef struct msg_s2c_st
{
long mtype; /* 用MSG_DATA或者MSG_EOT进行判断*/
char data[DATAMAX];
int datalen;
/*
datalen >0 :data包
datalen =0 :eot包
*/
}msg_data_t;
#endif
信号量
路径:c/linux_c/ipc/xsi/sem,P(取资源)V(还资源)操作。
int semget(key_t key, int nsems, int semflg);
int semop(int semid, struct sembuf *sops, size_t nsops);
int semtimedop(int semid, struct sembuf *sops, size_t nsops,
const struct timespec *timeout);
int semctl(int semid, int semnum, int cmd, ...);
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <pthread.h>
#include <sys/wait.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#define FILENAME "/tmp/out"
#define PROCNUM (10)
static int semid;
static void P()
{
struct sembuf op;
op.sem_num = 0;
op.sem_op = -1;
op.sem_flg = 0;
int ret;
ret = semop(semid,&op,1);
while(ret<0)
{
if(errno != EINTR || errno != EAGAIN)
{
perror("semop");
exit(1);
}
}
}
static void V()
{
struct sembuf op;
int ret;
op.sem_num = 0;
op.sem_op = 1;
op.sem_flg = 0;
ret = semop(semid,&op,1);
if(ret<0)
{
perror("semop");
exit(1);
}
}
void func_add(void);
int main()
{
pid_t pid;
int i,j,mark;
int err;
semid = semget(IPC_PRIVATE,1,0600); //匿名ipc,用于父子进程通信
if(semid <0)
{
perror("semget");
exit(1);
}
int ret;
ret = semctl(semid,0,SETVAL,1);//设置数组0下标的值为1.
if(ret<0)
{
perror("semctl");
exit(1);
}
for(i =0;i