Linux: 进程间通信

来源:互联网 发布:js导出csv 编辑:程序博客网 时间:2024/06/01 20:42


进程:

目的:

  1. 数据传输: 一个进程数据发送给另一个进程.
  2. 资源的共享: 多个进程共享同样的资源.
  3. 通知事件: 一个进程向另一个或一组进程发送消息.
  4. 进程控制: 控制另一个进程.

现在Linux使用的进程间通信方式(IPC): 

 1.  管道(pipe),无名管道(FIFO).

 2. 信号(signal).

 3. 消息队列.

 4. 共享内存.

 5.  信号量.

 6.  套接字(socket):网络套接字(TCP:流式套接字stream , UDP: 数据报套接字dgram)

 

一.管道通信(先进先出,单向)

1.  无名管道(只能在父子进程间使用):

int pipe(intfiledis[2])

filedis[0]:读管道.

filedis[1]:写管道.

关闭管道:close(filedis[0]);

                   close(filedis[1]);

必须先pipe() 再  fork()

否则子进程无法继承文件描述符.

 

2.  有名管道(不相关的进程也能交换数据):

#include<sys/types.h>

#include<sys/stat.h>

int mkfifo(constchar *pathname, mode_t mode)

pathname:文件名.

mode:文件属性.

 

例子:

有名管道读写:

//read

#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define FIFO "/home/benson/test/ben1"

main(int argc,char** argv)
{
 char buf_r[100];
 int  fd;
 int  nread;
 
 
 if( ( mkfifo(FIFO,O_CREAT|O_EXCL)< 0) && (errno !=EEXIST))
  printf("cannot createfifoserver\n");
 
 printf("Preparing for reading bytes...\n");
 
 memset(buf_r,0,sizeof(buf_r));
 
 
 fd = open(FIFO,O_RDONLY|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("nodata yet\n");
  }
  printf("read %s fromFIFO\n",buf_r);
  sleep(1);
 
 pause();
 unlink(FIFO); //删除文件
}

//write

#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define FIFO_SERVER "/home/benson/test/ben1"

main(int argc,char** argv)
{
 int fd;
 char w_buf[100];
 int nwrite;
  
 
 fd =open(FIFO_SERVER,O_WRONLY|O_NONBLOCK,0);
 
 if( argc == 1)
 {
  printf("Please sendsomething\n");
  exit(-1);
 }
 
 strcpy(w_buf,argv[1]);
 
 
 if( (nwrite = write(fd,w_buf,100)) == -1)
 {
  if( errno == EAGAIN)
   printf("TheFIFO has not been read yet.Please try later\n");
 }
 else
  printf("write %s to theFIFO\n",w_buf);
}

 

二.信号通讯

几种常见的信号:

                       SIGHUP:从终端上发出的结束信号.

                       SIGINT:来自键盘的中断信号.

                       SIGKILL:该信号结束接受信号的进程.

                       SIGTERM:kill命令发出的信号.

                      SIGCHLD:标识子进程停止或结束的信号.

                      SIGSTOP:来自键盘(ctrl + Z)或调试程序停止执行的信号.

信号处理:

  1. 忽略信号. (SIGKILL 和 SIGSTOP 不能被忽略)
  2. 执行用户希望的动作.
  3. 执行系统默认的动作.(多数为终止该进程)

 

信号发送:#include<sys/types.h>

                  #include <signal.h>

int kill(pid_tpid, int signo)

int raise(intsigno)

kill:可以向自身或者是其他进程发送信号.

raise:只可以向自己发送信号.

kill的pid值的情况:

  1. pid> 0 :将信号发送给进程ID为pid的进程.
  2. pid == 0:信号发送给同组的进程.
  3. pid< 0 :信号发送给|pid| (绝对值)的进程.
  4. pid == -1:信号发送给所有的进程.

 

信号等待:#include<unistd.h>

unsignedint alarm(unsigned int seconds)

seconds:经过指定秒数后产生信号.

intpause(void)

只有执行了一个信号,函数pause是进程等待收到一个信号为止,挂起才结束.

 

信号处理:#include<signal.h>

void (*signal(int signo ,  void (*func)(int) ))  (int)

====>>typedef void (*sighandler_t)(int)   (经过宏定义变成下面)

====》》sighandler_t  signal(int signum , sighandler_thandler)

  1. func可能的值:SIG_IGN(忽略信号) ,SIG_DFL(按系统默认方式处理) , 自定义的函数名

 

三.共享内存:多个进程共享一部分的物理内存,共享内存是进程间数据共享的一种最快的方法.

 1. 创建内存:#include <sys/ipc.h>
                   #include<sty/shm.h>

int shmget(key_tkey, int size, int shmflg)

key:IPC_PRIVATE.

size:内存的大小.

shmflg:内存的属性.(文件属性)

返回值:返回共享内存的标识符,否则返回-1.

 

  2. 内存的映射:

int shmat(intshmid, char *shmaddr, int flag)

shmid:共享内存的标识符.

flag:以什么方式映射内存. 一般为0

shmaddr:一般为0(系统帮找一块)

解除映射:int shmdt(char *shmaddr) (shmaddr从shmat中来.)

 

四.消息队列:1.POSIX消息队列,2.系统V(5)消息队列(Linux特有)

 1. 获取键值:#include<sys/types.h>

                           #include<sys/ipc.h>

 key_t ftok(char *pathname,charproj)

功能:返回文件名对应的键值.

pathname:文件名.

proj:项目名.

 

 2. 打开消息队列:#include<sys/msg.h>

int msgget(key_tkey, int msgflag)

key:键值.(从ftok中获取)

msgflg:属性.

 IPC_CREAT:(创建新的消息队列)

 IPC_EXCL:(与IPC_CREAT一起使用,如果队列已经存在,则返回错误)

 IPC_NOWAIT:(读写消息队列要求无法满足,返回错误)

返回值:与键值相对应的消息队列描述符.

 

 3. 发送消息:#include<sys/msg.h>

int msgsnd(intmsqid, struct msgbuf *msgp, int msgsize, intmsgflg)

msgid:已经打开的消息队列,从msgget中获取.

msgp:存放消息的结构.

msgsize:消息的大小.

msgflg:属性,一般为IPC_NOWAIT

structmsgbuf

{

       long mtype;  //消息类型

       charmtext[1];   //消息数据的首地址

};

 

 4. 接收消息

int msgrcv(intmsgid, struct msgbuf * msgp, int msgsize, long msgtyp, intmsgflg)

msgtyp:可以为getpid()

其余同上~~

 

#include <sys/types.h>
#include <sys/msg.h>
#include <unistd.h>

struct msg_buf
    {
       int mtype;
       char data[255];
    };
 
int main()
{
       key_t key;
       int msgid;
       int ret;
       struct msg_buf msgbuf;
 
       key = ftok("/tmp/2",'a');
       printf("key =[%x]\n",key);
       msgid =msgget(key,IPC_CREAT|0666);   

       if(msgid==-1)
       {
               printf("create error\n");
               return -1;
       }
 
       msgbuf.mtype = getpid();
       strcpy(msgbuf.data,"test haha");
       ret =msgsnd(msgid,&msgbuf,sizeof(msgbuf.data),IPC_NOWAIT);
       if(ret == -1)
       {
               printf("send message err\n");
               return -1;
       }
 
       memset(&msgbuf,0,sizeof(msgbuf));
       ret =msgrcv(msgid,&msgbuf,sizeof(msgbuf.data),getpid(),IPC_NOWAIT);
       if(ret == -1)
       {
               printf("recv message err\n");
               return -1;
       }
       printf("recv msg =[%s]\n",msgbuf.data);
 
}

0 0
原创粉丝点击