Linux: 进程间通信


进程:

目的:

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

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

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

 2.  信号(signal).

 3.  消息队列.

 4.  共享内存.

 5.  信号量.

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

 

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

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

int pipe(int filedis[2])

filedis[0]:读管道.

filedis[1]:写管道.

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

                    close(filedis[1]);

必须先pipe()  再  fork()

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

 

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

#include <sys/types.h>

#include <sys/stat.h>

int mkfifo(const char *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 create fifoserver\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("no data yet\n");
  }
  printf("read %s from FIFO\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 send something\n");
  exit(-1);
 }
 
 strcpy(w_buf,argv[1]);
 
 
 if( (nwrite = write(fd,w_buf,100)) == -1)
 {
  if( errno == EAGAIN)
   printf("The FIFO has not been read yet.Please try later\n");
 }
 else
  printf("write %s to the FIFO\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_t pid, int signo)

int raise(int signo)

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

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

kill的pid值的情况:

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

 

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

unsigned int alarm(unsigned int seconds)

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

int pause(void)

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

 

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

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

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

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

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

 

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

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

int shmget(key_t key, int size, int shmflg)

key:IPC_PRIVATE.

size:内存的大小.

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

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

 

  2.  内存的映射:

int shmat(int shmid, 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,char proj)

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

pathname:文件名.

proj:项目名.

 

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

int msgget(key_t key, int msgflag)

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

msgflg:属性.

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

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

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

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

 

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

int msgsnd(int msqid, struct msgbuf *msgp, int msgsize, int msgflg)

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

msgp:存放消息的结构.

msgsize:消息的大小.

msgflg:属性,一般为IPC_NOWAIT

struct msgbuf

{

        long mtype;   //消息类型

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

};

 

 4. 接收消息

int msgrcv(int msgid, struct msgbuf * msgp, int msgsize, long msgtyp, int msgflg)

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
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值