Linux进程间的通信

进程进行通信的原因:
       数据传输,资源共享,通知事件,进程控制
posix(portable operationing system interface):可移植的操作系统接口

进程通信方式:
                             管道和有名管道
                             信号
                        消息队列
                             共享内存
                             信号量
                             套接字(socket)
------------------------------------------------------------
管道通信:管道是单向的,先进先出
无名管道:用于父进程和子进程间的通信
有名管道:用于任意两个进程间的通信
------------------------------------------------------
#include<stdio.h>
#inlcude <stdlib.h>
#include <errno.h>
#inlcude <unistd.h> 
无名管道:
//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 <stdio.h>t
#include <stdlib.h>
#include <sys/types.h>
#include <errno.h>
#include <unistd.h>
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 <sys/types.h>
#include <sys/stat.h>
int mkfifo(const char * pathname.mode_t mode)
//打开fifo时,非阻塞标志:O_NONBLOCK
1.没有使用 O_NONBLOCK:访问要求无法满足时,进程将阻塞
2.有使用 O_NONBLOCK:访问要求无法满足时,进程不阻塞,立即出错返回,error是:     ENXIO

例子:fifo_read.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/type.h>
#include <sys/stat.h>
#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 <sys/types.h>
#include <signal.h>
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 <unistd.h>
unsigned int alarm(unsigned int seconds)
//seconds:经过多少秒后发送信号
----------------------------------
pause():子进程等待,直到受到下一个信号为止
-------------------------------------------
-------------------------------------------
--------------------------------------------
信号处理:
方式一:使用简单的signal函数
方式二:使用信号集的函数组
/////////////////////////////////////////////////////
#include <signal.h>
void (*signal(int signo,void(*func)(int)))(int)
//上句代码的理解:typedef void(*signalhander_t )(int)
                               signalehander_t signale(int signanum,sighander_t  hander)
----------------------------------------------------------
//#include <signal.h>
#inlcude <stdio.h>
#inlcude <stdlib.h>
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,)//卸载不用的内存空间

猜你喜欢

转载自blog.csdn.net/XJH0918/article/details/48543985