linux 进程通信

一 进程间通信
1.1 概念
    进程间由于其资源都是相互独立的,所以想要实现进程间通信
    就必须找到他们共享的资源(内核资源),通过读写内核资源
    来实现,进程间的通信
1.2 分类
    1> 传统通信方式
        无名管道
        有名管道
        信号
    2> IPC第五代通信
        消息队列
        共享内存
        信号量
        套接字(网络通信)
1.3 前提
    1> 单工:通信双方,一方只能接收,另一方只能发送
    2> 半双工:通信双方,同一时刻,一方只能接收,另一方只能发送
    3> 全双工:通信双方,同一时刻,双方既能接收也能发送消息
1.4 无名管道
1> 概念
    (1)无名管道是一种用于亲缘间进程的半双工通信方式。
    (2)无名管道文件创建后,其是一个特殊的文件,在文件系统中
       没有实质文件的体现.
    (3)无名管道的大小为64k(64*1024)个字节,一旦写满后,再往管道中
       写数据,会造成write函数阻塞,当管道写满后,至少从管道中读取4k个数据后
       才能继续向管道中写数据.
    (4)当读端关闭,继续往管道中写数据,会造成"管道破裂"(程序异常退出)
    (5)当写段关闭,继续从管道中读数据,read函数会直接返回,
       写数据,write函数返回-1。
    (6)管道符合先进先出的原则,数据读走后就会消失。
2> API
【1】pipe
头文件:#include <unistd.h>
原型:int pipe(int fildes[2]);
功能:创建一个无名管道
参数:fildes:文件描述符集合
          读端:fildes[0]
          写端:fildes[1]
返回值:
    成功:返回0
    失败:返回-1

练习:实现父子间进程通信,父子间进程可以互发消息
提示:
    1.创建一个子进程
    2.创建两个管道

1.5 有名管道
 1> 概念
    (1)有名管道主要用于非亲缘间进程的通信,和无名管道的性质类似
       也是一种半双工通信方式
    (2)有名管道在文件系统上有文件的体现,但是不能对管道文件
       操作读写指针的偏移。
    (3)管道文件不是真正的文件,在不是在磁盘上进行存储,而是
        在内存中进行存储,也就是说,当进程结束后,管道文件中的
        数据将全部丢失。
    (4)有名管道的读端和写端默认都是关闭的,需要手动打开(open)
    (5)有名管道当其读写端有一端没有打开时,open函数会阻塞等待另外
        一端的打开。
 2> API
【1】mkfifo
头文件:#include <sys/types.h>
       #include <sys/stat.h>
原型:int mkfifo(const char *pathname, mode_t mode);
功能:创建一个有名管道文件
(注意:mkfifo也可以当作命令使用)
(使用方法:mkfifo + pathname)
参数:
    pathname:路径和名称
    mode:权限 --->0664
返回值:
    成功:返回0
    失败:返回-1

练习:利用有名管道实现两个非亲缘进程(两个.c文件)的互消息
      要求进程A可以连续给进程B发消息。
提示:
    1.创建两个有名管道
    2.每个进程再创建一个子进程(或者线程)

作业:利用有名管道实现两个非亲缘进程(两个.c文件)的互发消息
      要求进程A可以连续给进程B发消息。
提示:
    1.创建两个有名管道
    2.每个进程再创建一个子线程(多线程)

1.6 进程间通信---信号
    1> 概念
    (1)信号是软件层对硬件层中断的一种模拟,是一种优先级高信号是软件层对硬件层中断的一种模拟,是一种优先级高
    的代码中断事件
    (2)信号的分类
         1) SIGHUP     2) SIGINT     3) SIGQUIT     4) SIGILL     5) SIGTRAP
         6) SIGABRT     7) SIGBUS     8) SIGFPE     9) SIGKILL    10) SIGUSR1
        11) SIGSEGV    12) SIGUSR2    13) SIGPIPE    14) SIGALRM    15) SIGTERM
        16) SIGSTKFLT    17) SIGCHLD    18) SIGCONT    19) SIGSTOP    20) SIGTSTP
        21) SIGTTIN    22) SIGTTOU    23) SIGURG    24) SIGXCPU    25) SIGXFSZ
        26) SIGVTALRM    27) SIGPROF    28) SIGWINCH    29) SIGIO    30) SIGPWR
        31) SIGSYS    34) SIGRTMIN    35) SIGRTMIN+1    36) SIGRTMIN+2    37) SIGRTMIN+3
        38) SIGRTMIN+4    39) SIGRTMIN+5    40) SIGRTMIN+6    41) SIGRTMIN+7    42) SIGRTMIN+8
        43) SIGRTMIN+9    44) SIGRTMIN+10    45) SIGRTMIN+11    46) SIGRTMIN+12    47) SIGRTMIN+13
        48) SIGRTMIN+14    49) SIGRTMIN+15    50) SIGRTMAX-14    51) SIGRTMAX-13    52) SIGRTMAX-12
        53) SIGRTMAX-11    54) SIGRTMAX-10    55) SIGRTMAX-9    56) SIGRTMAX-8    57) SIGRTMAX-7
        58) SIGRTMAX-6    59) SIGRTMAX-5    60) SIGRTMAX-4    61) SIGRTMAX-3    62) SIGRTMAX-2
        63) SIGRTMAX-1    64) SIGRTMAX            
    (3)信号的处理方式:
        <1> 忽略:将这个信号忽略,不处理
        <2> 捕捉:当信号触发后,执行特定注册好的程序
        <3> 默认:不特殊处理,执行默认功能
        注意:某些信号无法被忽略或者捕捉:例如:SIGKILL
    2> API
【1】signal
头文件:#include <signal.h>
//函数指针函数
原型:void ( *signal(int sig, void (*func)(int)) )(int); 
功能:处理(注册)一个信号
参数:
    sig:信号值:64个

    void (*func)(int):处理方式
        SIG_IGN:忽略
        SIG_DFL:默认
        当触发信号后,调用信号处理函数:捕捉
返回值:成功:返回上一次信号处理的值
        例如:上一次处理的是捕捉,则这一次signal的结果为上次捕捉的函数
              上一次处理为忽略或者默认你,则这一次signal成功返回0
        失败:返回SIG_ERR
练习:完成父进程回收子进程的最佳处理方式(mkfifo程序)

【2】alarm
头文件:#include <unistd.h>
原型:unsigned int alarm(unsigned int seconds); 
功能:alarm()以秒为单位将SIGALRM信号传递给调用进程。
参数:
    seconds:单位:秒
返回值:返回定时器剩余的秒数
        
注意:1> 如果seconds为零,则取消所有挂起的alarm。
      2> 在任何情况下,任何先前设置的alarm()都被取消。

1.7 IPC第五代通信---->消息队列
1>概念
    (1)消息队列用一种可用于非亲缘间的全双工通信方式,消息队列中
       是以链队列的形式保存数据,当我们将数据写入消息队列后,数据并不会丢失
    (2)消息队列可以按照先进先出的原则读取数据,也可以按照用户自定义的
       的想法从队列中读取数据
       
    (3)ipcs:用于查看第五代通信属性
         edu118@ubuntu:~/230529/day10$ ipcs
            --------- 消息队列 -----------
            键        msqid      拥有者  权限     已用字节数 消息      

            ------------ 共享内存段 --------------
            键        shmid      拥有者  权限     字节     连接数  状态      
            0x00000000 557056     edu118     600        16777216   2            
            0x00000000 655361     edu118     600        524288     2          目
            0x00000000 491522     edu118     600        524288     2          目
            0x00000000 1179651    edu118     600        524288     2          目
            0x00000000 884740     edu118     600        524288     2          目
            0x00000000 983045     edu118     600        524288     2          目
            0x00000000 1081350    edu118     600        134217728  2          目
            0x00000000 1343495    edu118     600        524288     2          目
            0x00000000 1441800    edu118     600        524288     2          目
            0x00000000 1703945    edu118     600        524288     2          目
            0x00000000 1802250    edu118     600        524288     2          目
            0x00000000 1835019    edu118     600        524288     2          目
            0x00000000 18776077   edu118     600        524288     2          目
            0x00000000 18841614   edu118     600        2097152    2          目
            0x00000000 23461903   edu118     600        74184      2          目
            0x00000000 23592976   edu118     600        524288     2          目

            --------- 信号量数组 -----------
            键        semid      拥有者  权限     nsems
    (4)ipcs的属性
        -p: 显示消息队列相关信息
        -s:显示信号量相关信息
        -m: 显示共享内存相关信息
    (5) ipcrm
        属性:
            -q:+ 消息队列ID   //删除某一个消息队列
            -s:+ 信号量集ID   //删除某一个信号量集
            -m: + 共享内存ID   //删除某一个共享内存
【1】ftok
头文件:#include <sys/types.h>
       #include <sys/ipc.h>
原型:key_t ftok(const char *pathname, int proj_id);
功能:生成一个密钥
参数:
    pathname:路径(一定要存在)
    proj_id :传一个字符(大于0)
返回值:
    成功:返回一个密钥值
    失败:返回-1
【2】msgget
头文件:#include <sys/msg.h>  
原型:int msgget(key_t key, int msgflg);
功能:创建一个消息队列
参数:
    key:ftok函数的返回值
    msgflg:
        IPC_CREAT:如果消息队列不存在,则创建之    
                   如果消息队列存在,则直接打开
        O_EXCL:如果文件存在则报错返回 ,返回EEXIST
    使用格式:IPC_CREAT|0664  //如果消息队列不存在,则创建之,如果消息队列存在,则直接打开
              IPC_CREAT|O_EXCL|0664 //如果消息队列不存在,则创建之,如果存在,则报错
返回值:
    成功:返回一个消息队列的ID号
    失败:返回-1
【3】msgsnd
头文件:#include <sys/msg.h>  
原型:int msgsnd(int msqid, const void *msgp, size_t msgsz, int ms
gflg);
功能:向消息队列中写数据
参数:
    msqid:目标消息队列ID号
    msgp:
        struct mymsg {
               long   mtype;       /* Message type. must > 0*/ 
               char   mtext[1];    /* Message text. 消息正文 */
           }
    msgsz:发送消息的长度
    msgflg:发送消息的方式
        IPC_NOWAIT:非阻塞 //当消息队列写满,直接返回
        0         :阻塞  //当消息队列写满,阻塞等待
返回值:
    成功:返回 0
    失败:返回-1        
【4】msgrcv
头文件:#include <sys/msg.h>
原型:ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp,int msgflg);
功能:从消息队列中读取数据
参数:
    msqid:目标消息队列ID号
    msgp:读取到的数据存放的地址:用户定义的结构体如下:
        struct mymsg {
               long   mtype;       /* Message type. must > 0*/ 
               char   mtext[1];    /* Message text. 消息正文 */
           }
    msgsz:读取最大的消息字节
    msgtyp:读取的消息的类型
            0:先进先出读取第一个消息
            >0:读取指定消息
            <0:如果msgtype小于0,则接收小于等于msgtype绝对值的最小类型的第一条消息。
    msgflg:        
        IPC_NOWAIT:非阻塞
        0         :阻塞
返回值:
    成功:返回实际读取到的字节个数
    失败:返回-1
【5】msgctl
头文件:#include <sys/types.h>
       #include <sys/ipc.h>
       #include <sys/msg.h>    
原型: int msgctl(int msqid, int cmd, struct msqid_ds *buf);
功能:控制消息队列
参数:
    msqid:目标消息队列ID号
    cmd:操作方式
        IPC_SET :设置消息队列中struct ipc_perm中的信息
            struct ipc_perm {
               key_t          __key;       /* Key supplied to msgget(2) */
               uid_t          uid;         /* Effective UID of owner */
               gid_t          gid;         /* Effective GID of owner */
               uid_t          cuid;        /* Effective UID of creator */
               gid_t          cgid;        /* Effective GID of creator */
               unsigned short mode;        /* Permissions */
               unsigned short __seq;       /* Sequence number */
           };

        IPC_STAT:获取消息队列struct msqid_ds中所有的信息
        IPC_RMID:用于删除目标消息队列,如果删除,第三参数写为NULL
    buf:
    struct msqid_ds {
               struct ipc_perm msg_perm;     /* Ownership and permissions */
               time_t          msg_stime;    /* Time of last msgsnd(2) */
               time_t          msg_rtime;    /* Time of last msgrcv(2) */
               time_t          msg_ctime;    /* Time of last change */
               unsigned long   __msg_cbytes; /* Current number of bytes in
                                                queue (nonstandard) */
               msgqnum_t       msg_qnum;     /* Current number of messages
                                                in queue */
               msglen_t        msg_qbytes;   /* Maximum number of bytes
                                                allowed in queue */
               pid_t           msg_lspid;    /* PID of last msgsnd(2) */
               pid_t           msg_lrpid;    /* PID of last msgrcv(2) */
           };
返回值:
    成功:返回0
    失败:返回-1
【6】kill
头文件:#include <sys/types.h>
       #include <signal.h>  
原型:int kill(pid_t pid, int sig);  A---B
功能:向指定的进程发送一个信号
参数:
    pid:目标进程号
    sig:信号值:10) SIGUSR1  12) SIGUSR2
返回值:
    成功:返回0
    失败:返回-1
作业:使用消息队列+信号实现两个进程互发消息(可以连续接收和发送)
提示:1.创建一个消息队列
      2.使用两种消息类型进行收发消息
      3.使用信号发送给另一个进程,提示另一个进程接收消息
      4.通信前先将自己的进程号发送给对端
1.8 IPC第五代通信---->共享内存
    1>概念
        用户通过映射内核空间的同一块区域映射到各自的用户空间
        ,然后用户向这块用户空间写数据,相当于向内核空间写数据
        如此,进程B从自己的用户空间读数据,相当于从内核空间读取
        数据,因为其对内核API调用少,所以效率更高,但是共享数据
        是不安全,需要增加同步和互斥机制。
    2>API
【1】shmget
头文件:#include <sys/ipc.h>
       #include <sys/shm.h>
原型:int shmget(key_t key, size_t size, int shmflg);
功能:创建或者打开一个共享内存
参数:
    key:由ftok函数产生的密钥
    size:创建共享内存的大小(一般为4k的整数倍),已经存在则无效
    shmflg:
        IPC_CREAT:如果消息队列不存在,则创建之    
                       如果消息队列存在,则直接打开
            O_EXCL:如果文件存在则报错返回 ,返回EEXIST
        使用格式:IPC_CREAT|0664  //如果共享内存不存在,则创建之,如果共享内存存在,则直接打开
                  IPC_CREAT|O_EXCL|0664 //如果共享内存不存在,则创建之,如果存在,则报错
返回值:    成功:返回共享内存的ID号
        失败:返回-1
        
【2】shmat
头文件:#include <sys/types.h>
       #include <sys/shm.h>
    
原型:void *shmat(int shmid, const void *shmaddr, int shmflg);
功能:建立虚拟映射
参数:
    shmid:目标共享内存ID号
    shmaddr:用户空间地址(写为NULL,操作系统会找一块合适的空间建立映射)
    shmflg:
        0:默认可读可写
        SHM_RDONLY:设置其共享内存段为只读权限。
        SHM_REMAP:替换现有映射段区域
返回值:
    成功:返回映射好的空间的首地址
    失败:返回(void *)-1
【3】shmdt
头文件:#include <sys/types.h>
       #include <sys/shm.h>
原型:int shmdt(const void *shmaddr);
功能:断开虚拟映射
参数:
    shmaddr:映射好空间的地址
返回值:
    成功:返回0
    失败:返回-1
【4】shmctl
头文件:#include <sys/ipc.h>
       #include <sys/shm.h>
原型:int shmctl(int shmid, int cmd, struct shmid_ds *buf);
功能:控制共享内存    
参数:
    shmid:目标共享内存ID号
    cmd:控制的方式
        IPC_STAT:获取shmid_ds所有信息
        IPC_SET: 设置shm_perm.uid,  shm_perm.gid, and (the least sig‐
                 nificant 9 bits of) shm_perm.mode
        IPC_RMID:删除共享内存(第三个参数填写为NULL)
    buf:
        struct shmid_ds {
               struct ipc_perm shm_perm;    /* Ownership and permissions */
               size_t          shm_segsz;   /* Size of segment (bytes) */
               time_t          shm_atime;   /* Last attach time */
               time_t          shm_dtime;   /* Last detach time */
               time_t          shm_ctime;   /* Last change time */
               pid_t           shm_cpid;    /* PID of creator */
               pid_t           shm_lpid;    /* PID of last shmat(2)/shmdt(2) */
               shmatt_t        shm_nattch;  /* No. of current attaches */
               ...
           };
        The ipc_perm structure is defined as  follows  (the  highlighted  fields  are  settable  using
       IPC_SET):
           struct ipc_perm {
               key_t          __key;    /* Key supplied to shmget(2) */
               uid_t          uid;      /* Effective UID of owner */
               gid_t          gid;      /* Effective GID of owner */
               uid_t          cuid;     /* Effective UID of creator */
               gid_t          cgid;     /* Effective GID of creator */
               unsigned short mode;     /* Permissions + SHM_DEST and
                                           SHM_LOCKED flags */
               unsigned short __seq;    /* Sequence number */
           };
返回值:
    成功:IPC_STAT,IPC_INFO成功:共享内存的ID号,其他成功:返回0
    失败:返回-1。

1.9 IPC第五代通信---->信号量集
【1】semget
头文件:#include <sys/types.h>
       #include <sys/ipc.h>
       #include <sys/sem.h>
原型:int semget(key_t key, int nsems, int semflg);
功能: 创建一个信号量集合
参数:
    key:ftok函数生成密钥
    nsems:信号灯的数量
    semflg:
        IPC_CREAT|0664  //如果信号量集不存在,则创建之,如果信号量集存在,则直接打开
        IPC_CREAT|O_EXCL|0664 //如果信号量集不存在,则创建之,如果存在,则报错
返回值:    
    成功:返回信号量集标识符
    失败:返回-1
【2】semctl
头文件:#include <sys/types.h>
       #include <sys/ipc.h>
       #include <sys/sem.h>
原型:int semctl(int semid, int semnum, int cmd, ...);
功能:控制信号量集
参数:
    semid:目标信号量集
    semnum:操作信号灯的序号(第一个信号灯为0,依次类推)
    cmd:控制的方式
        SETVAL:设置信号灯的初值
        GETVAL: 获取semnum信号量的资源状态(无需设置第四个参数)
        IPC_STAT: 读取 struct semid_ds所有信息
        IPC_SET: 设置shm_perm的值
        
    ...:可变参数,此处是一个联合体(cmd用到哪种方法,则填写结构体中哪个成员)
        union semun {
               int              val;    /* Value for SETVAL */
               struct semid_ds *buf;    /* Buffer for IPC_STAT, IPC_SET */
               unsigned short  *array;  /* Array for GETALL, SETALL */
               struct seminfo  *__buf;  /* Buffer for IPC_INFO
                                           (Linux-specific) */
           };
返回值:    
       失败:返回-1.
       成功:根据具体的cmd参数的值返回不同的结果:
           GETNCNT   the value of semncnt.
           GETPID    the value of sempid.
           GETVAL    the value of semval.
           GETZCNT   the value of semzcnt.
           IPC_INFO  the index of the highest used entry in the kernel's internal array record‐
                     ing information about all semaphore sets.  (This information can  be  used
                     with  repeated  SEM_STAT  operations to obtain information about all sema‐
                     phore sets on the system.)

           SEM_INFO  as for IPC_INFO.
           SEM_STAT  the identifier of the semaphore set whose index was given in semid.
            除上述外的cmd,成功返回0.
【3】semop
头文件:#include <sys/types.h>
       #include <sys/ipc.h>
       #include <sys/sem.h>
原型:int semop(int semid, struct sembuf *sops, size_t nsops);
功能:按照给定的参数,申请或者释放资源(pv操作)
参数:
    semid:目标信号量集
    sops : 
    struct sembuf{//需要用户自定义
        unsigned short sem_num;  /* semaphore number */
        short          sem_op;   /* semaphore operation */
        short          sem_flg;  /* operation flags */
    };
    nsops:信号灯的数量(如果操作的信号灯数量大于1,则第二个参数传结构体数组)
返回值:    
    成功:返回0
    失败:返回-1

作业:使用共享内存+信号量实现文件传输


 

 共享内存

 

 

 信号量集

 

 

作业

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值