进程进行通信的原因:
数据传输,资源共享,通知事件,进程控制
posix(portable operationing system interface):可移植的操作系统接口
进程通信方式:
管道和有名管道
信号
消息队列
共享内存
信号量
套接字(socket)
------------------------------------------------------------
管道通信:管道是单向的,先进先出
无名管道:用于父进程和子进程间的通信
有名管道:用于任意两个进程间的通信
------------------------------------------------------
#include
#inlcude
#include
#inlcude
无名管道:
//int pipe(int filedis[2])
//当一个管道被创建时,它会创建两个文件操作符,filedis[0]用于读管道;
filedis[1]用于写管道;
//int pipe_fd[2];
//if(pipe(pipe_fd)<0){
printf("pipe create fail");
return -1;
}
else{
printf("pipe create success");
close(pipe_fd[0]);//关闭读一端的管道(子进程)
close(pipe_fd[1]);//关闭写的一端的管道(父进程)
}
-------------------------------------------------------
///无名管道的例子
#include t
#include
#include
#include
#include
int main()
{
pipe_t pipe_fd[2];
pid_t pid;
char* buf_r[100];
int num_r;
memset(buf_r,0,sizeof(buf_r));
if(pipe(pipe_fd)<0)
{
printf("pipe create failed!\n");
return -1;
}
if(pid=fork()==0)
{
printf("\n");
close(pipe_fd[1]);
if(num_r=read(pid_fd[0],buf_r,100)>0)
{
printf("%d numbers pipe read %s\n",num_r,buf_r);
}
close(pipe_fd[0]);
}
if(pid>0)
{
close(pipe_fd[0]);
if(read(pipe_fd[0],"hello",5)!=-1)
printf("pipe can be read hello!\n");
if(read(pipe_fd[0],"pipe",5)!=-1)
printf("pipe can be read pipe!\n");
close(pipe_fd[1]);
}
}
**注意事项:在父进程和子进程中,必须在系统调用fork前调用管道,否则子进程不会继承文件描述符;
原因是:如果先调用fork的话,会创建出子进程,也就是有两个管道,父进程管道和子进程管道,两者就没有了交集,子进程就不去继承了和父进程同一级别的文件描述符了。
-
-------------------------------------------------
----------------------------------
命名管道:
#include
#include
int mkfifo(const char * pathname.mode_t mode)
//打开fifo时,非阻塞标志:O_NONBLOCK
1.没有使用
O_NONBLOCK:访问要求无法满足时,进程将阻塞
2.有使用
O_NONBLOCK:访问要求无法满足时,进程不阻塞,立即出错返回,error是:
ENXIO
例子:fifo_read.c
#include
#include
#include
#include
#include
#include
#include
#define FIFO /home/xie/test/2015-6-9/mkfifo
int main(int argc,char* argv[])
{
char buf_r[100];
int fd;
int nread;
//创建管道
if(mkfifo(FIFO,O_CREAT|O_EXCL)<0)&&(errno!=EEXIST)
printf("can not create fifoserver!\n");
printf("preparing for reading bytes!\n");
memset(buf_r,0,sizeof(buf_r));
fd=open(FIFO,O_RWONLY|O_NONBLOCK,0);
if(fd==-1)
{
perror("open");
exit(-1);
}
while(1)
{
memset(buf_r,0,sizeof(buf_r));
if(nread=read(fd,buf_r,100)==-1)
{
if(errno==EAGAIN)
printf("no data!\n");
}
printf("read %s from FIFO\n",buf_r);
sleep(1);
}
pause();
}
fifo_write.c
int main(int argc,char *argv[])
{
char buf_w[100];
int fd;
int nwrite;
fd=open(FIFO,O_RDNOLY|O_NONBLOCK,0);
if(argc==1)
{
printf("please send message !\n");
exit(-1);
}
strcpy(buf_w,argv[1]);
if(nwrite=write(fd,buf_w.100)==-1)
{
if(errno==EAGAIN)
printf("the fifo has not been read!\n");
}
else
printf("write %s to read!\n",buf_w);
}
--------------------
-----------------------------------------------------
------------------------------------------------------------------------------
信号:signal
小tips:1.在程序在循环输出时,用“ctrl+c”中断的原因是:系统产生了siginterrupt信号
2.用指令“ps -aux”查看进程号
信号产生的形式:用户按下按键;硬件异常产生信号,进程用kill函数产生信号;进程用kill命令产生信号
---------------------------
信号发送函数:kill raise alarm
区别:kill既可以给自己发信号,也可以给别的进程发信号;raise只能给自己发信号。
//#include
#include
int kill(pid_t pid,int signo);
int raise (int signo);
//在kill中pid的取值情况:
pid>0 将信号发送给进程ID为pid的进程
pid==0 将信号发送给同组的进程
pid<0将信号送给其进程组ID等于pid绝对值的进程
pid==-1 将信号发给所有的进程
alarm:
#include
unsigned int alarm(unsigned int seconds)
//seconds:经过多少秒后发送信号
----------------------------------
pause():子进程等待,直到受到下一个信号为止
-------------------------------------------
-------------------------------------------
--------------------------------------------
信号处理:
方式一:使用简单的signal函数
方式二:使用信号集的函数组
/////////////////////////////////////////////////////
#include
void (*signal(int signo,void(*func)(int)))(int)
//上句代码的理解:typedef void(*signalhander_t )(int)
signalehander_t signale(int signanum,sighander_t hander)
----------------------------------------------------------
//#include
#inlcude
#inlcude
void my_signal(int sign_no)
{
if(sign_no==SIGINT)
printf("i have get sigint!\n");
else if(sign_no==SIGQUIT
)
printf("i have get SIGQUIT\n");
}
int main()
{
printf("waiting for signal !\n");
signal(SIGINT,
my_signal
);
signal(SIGQUIT,my_signal);
pause(0);
exit(0);
}
------------------------------------------------------------------
-----------------------------------------------------------------------
进程通信-共享内存
实现步骤:1.创建共享内存,使用shmget()
2.映射共享内存,使用shmat()
-----------------------------------
1.创建共享内存
//int shmget(key_t key,int size,int shmflg)
2.
//int shmat(int shmid,char *shmaddr,int flags)//如果成功,则是返回共享内存映射到进程中的地址,如果失败,则是返回-1
//shmid:shmat函数返货的共享存储标志符号
//flag:决定以什么方式来确定映射的地址,通常都是0
int shmdt(char *shmaddr,)//卸载不用的内存空间