Linux-LPC通信

dup2 () 句柄重定向

会把第一个绑定的句柄关闭了 在重定向

popen() 获取进程句柄

运行一个命令 返回命令结果

  1. FILE* finput = popen("echo -e texe!","r");
  2. read(fileno(finput),buf,100);

fileno() 获取此句柄

无名管道 pipe

简单传输速度快

  • 无名管道 (pipe) :只有创建该管道的查询,才能找到该管道(亲缘进程管道)
  • 如果 fork 一个新进程就必须 每一个进程都必须关闭一个 pipe的 fd
  • 只能单向传输
  • 如果对方 把 两个pipe fd 都关闭 当 要读写时 就会立马退出 并且收到 SIGPIPE信号
  1. int pipe_fd[2];
  2. pipe(pipe_fd); //创建pipe 管道
  3. read(pipe_fd[0],buf,SIZ,0);//从管道中读取信息
  4. close(pipe_fd[1]); //关闭 一个pipe

有名管道 fifo

没有办法实现双向通信 传输速度慢

  • FIFO 是依赖于文件系统

和普通文件一样 拥有文件权限和其他属性,所有程序都可以通过fifo 的fd来找到有名管道

  • 命令行创建一个 有名管道 mknod FIFOTEST p
    • p 代表管道文件
  • fifo 必须 两端都同时打开 fifo 是 才能写进管道 否则就会阻塞 等待 其他进程打开
  1. int ret = mkfifo(./file.tmp,0666|S_IFIFO);//创建 fifo 管道文件
  2. int fd = open(./file.tmp,O_WRONLY|O_CREAT|0644);//打开 fifo管道
  • fifo 是一个文件,存储信息在内存中
  • 只能单向通信
  • 只能进行少量数据传输
  • 只能一对一传输
  • 两个进程,中途退出一个进程,未退出的一段如果是写操作的话,返回sigpipe信息
  • 未退出的一端如果是阻塞读操作的话,该操作不会继续阻塞,而直接返回0

system v ipc XSI消息队列

system v 和 ipc 共同的结构体

struct msqid_ds

  1. struct msqid_ds { // 消息结构体链表
  2. struct ipc_perm msg_perm; // 描述当前 msg 的权限
  3. time_t msg_stime; // 最后发送时间
  4. time_t msg_rtime; // 最后接收时间
  5. time_t msg_ctime; // 最后改变时间
  6. unsigned long __msg_cbytes; // 消息的字节数
  7. msgqnum_t msg_qnum; // 消息的个数
  8. msglen_t msg_qbytes; // 最大的字节数
  9. pid_t msg_lspid; // 最后一个发送进程的PID
  10. pid_t msg_lrpid; // 最后一个接收的进程的PID
  11. struct msg * msq_first ; // 头指针
  12. struct msg * msq_last ; // 尾指针
  13. };
  • 拥有者及权限对象

struct ipc_perm

  1. struct ipc_perm
  2. {
  3. __kernel_key_t key;// 当前的 key
  4. __kernel_uid_t uid;//用户id
  5. __kernel_gid_t gid;//组id
  6. __kernel_uid_t cuid;//当前用户id
  7. __kernel_gid_t cgid;//当前组id
  8. __kernel_mode_t mode; // 属性类型 读 写 属性
  9. unsigned short seq;
  10. };

优点和缺点

优点:
1. 消息队列是两个不相关进程之间传递数据的有效渠道.
2. 与命名管道相比,具有的优势是:
独立于发送以及接收进程而存在;
消除命名管道的打开以及关闭而存在的困难;
可以提前查看紧急信息;
避免命名管道的同步以及阻塞问题;
缺点:
与命名管道一样,每个数据块都有一个最大

  1. 度限制;
  2. 系统中所有队列包含的全部数据块长度也有一个上限;
  • 创建key
  • key :通信双方约定好的值,32位的整形数据
  • id :系统会为IPC分配一个唯一的ID,通信双方都需要知道ID才能使用当前IPC方法,创建者会返回当前ID值,
  • 使用命令 lpcs 可以查看所有 共享内存的字段
  1. #include <sys/types.h>
  2. #include <sys/ipc.h>
  3. key_t ftok(const char *pathname, int proj_id);
  4. pathname: 路径
  5. proj_id
  6. key 31-24 proj_id 8
  7. key 23-16 st_dev属性的低8
  8. key 15-0 st_ino属性的低16位;
  • 创建对象:
    int msgget(key_t key, int msgflg);
  1. #include <sys/types.h>
  2. #include <sys/ipc.h>
  3. #include <sys/msg.h>
  4. int msgget(key_t key, int msgflg);
  5. 参数1 key_t key
  6. 参数2int msgflg 确定消息队列的访问权限,
  7. IPC_CREAT 找到当前的key对应的IPC,如果没有IPC则进行创建
  8. IPC_EXCL 如果存在则返回失败
  9. IPC_NOWAIT 返回值为当前ipc对应的id值;
  10. msgget(key,0600|IPC_CREAT);
  • 设置对象:
    1. int msgctl(int msqid,int cmd,struct msqid_ds *buf);
    2. cmd:
    3. IPC_RMID 删除
    4. IPC_SET 设置ipc_perm参数
    5. IPC_STAT 获取ipc_perm参数
    6. IPC_INFO 获取ipc信息 ipc
  • 使用对象:
    1. 发送
      int msgsnd(int msqid,const void *msg_ptr,size_t sz,int msgflg);
      参数 sz:只是发送数据的长度 而不是全结构体长度
      msqid : 是 msgget的返回值 用于发送
      1. struct msgbuf
      2. {
      3. long mtype; // 发送消息的类型
      4. char mtext[1]; // 发送的数据
  1. 接收
  • ssizet msgrcv(int msqid, void _msgp, size_t msgsz, long msgtyp,int msgflg);
  1. ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp,int msgflg);
  2. msqid: 从哪一个 消息队列中收;
  3. msgp: 收取存放的结构体;
  4. msgsz:收取的大小;
  5. msgtyp:收取的类型

msgtyp 0 默认接收第一条消息
msgtyp > 0 接收第一条msgtyp消息
msgtyp < 0 接收小于msgtyp绝对值的消息

XSL信号量

概念:

  • 实现进程间同步
  • 表示系统可用资源的个数

对象:

  1. struct semid_ds {
  2. struct ipc_perm sem_perm; //和IPC权限一样
  3. time_t sem_otime;//最后一次调用信号操作的时间
  4. time_t sem_ctime; // 最后一次信号改变的时间
  5. unsigned long sem_nsems; //信号的个数
  6. struct sem * sem_base;// 单向指针 指向信号头节点
  7. };
  8. struct sem{
  9. int semval // 信号量的值
  10. int sempid // 最近一个操作的进程号
  11. }

对象操作

  • 创建对象: 创建信号对象

int semget(key_t k,int n,int semflag);

  1. #include <sys/ipc.h>
  2. #include <sys/sem.h>
  3. int semget(key_t key, int nsems, int semflg);
  4. nsems:创建信号的个数
  5. semflg:权限 IPC_CREAT
  • 设置对象:

int semctl(int sid,int semnum,int cmd,union semun a);

  1. int semctl(int sid,int semnum,int cmd,union semun a);
  2. union semun {
  3. int val; /* 信号的值 */
  4. struct semid_ds *buf; /* Buffer for IPC_STAT, IPC_SET */
  5. unsigned short* array; /* Array for GETALL, SETALL */
  6. struct seminfo *__buf; /* Buffer for IPC_INFO*/
  7. };
  8. cmd 如果对于整个信号量集合,则有如下设置方法
  9. IPC_STAT ipc_perm
  10. IPC_SET ipc_perm
  11. IPC_RMID
  12. IPC_INFO 信号量的系统信息
  13. cmd 如果对于单个信号量集合,则有如下设置方法
  14. GETPID 获取信号拥有者的PID
  15. semnum:参数无效
  16. GETVAL 获取信号的值 并且返回信号的值
  17. semnum:获取第几个信号的值
  18. GETALL 获取所有信号的值
  19. semnum0
  20. semun: 存储信号的地址
  21. SETVAL 设置某一个信号的值
  22. semnum:设置第几个信号的值
  23. semun 设置的值
  24. SETALL 设置所有信号的值
  25. semnum0
  26. semun 设置的值
  • 使用对象
  1. int semop(int s,struct sembuf *sb,size _t n);
  2. s:操作信号的id;
  3. n:第几个信号
  4. struct sembuf{
  5. unsigned short int sem_num; //信号的值
  6. short int sem_op; //选项
  7. short int sem_flg; //权限
  8. // sem_flg 的值为 SEM_UNDO 时 当当前进程退出时 撤回当前进程使用的所有资源
  9. };
  10. sem_op:的值
  11. + 表示进行加
  12. - 表示进行减

XSI共享内存

  • 数据量最大
  • 传输最快
  • mmap

共享内存对象

  1. struct shmid_ds {
  2. struct ipc_perm shm_perm; /* operation perms */
  3. int shm_segsz; /* size of segment (bytes) */
  4. __kernel_time_t shm_atime; /* last attach time */
  5. __kernel_time_t shm_dtime; /* last detach time */
  6. __kernel_time_t shm_ctime; /* last change time */
  7. __kernel_ipc_pid_t shm_cpid; /* pid of creator */
  8. __kernel_ipc_pid_t shm_lpid; /* pid of last operator */
  9. unsigned short shm_nattch; /* no. of current attaches */
  10. }

创建共享内存

int shmget(key_t key, size_t size, int shmflg);
共享内存的权限

  1. #include <sys/ipc.h>
  2. #include <sys/shm.h>
  3. int shmget(key_t key, size_t size, int shmflg);
  4. shmflg:权限
  5. SHM_R
  6. SHM_W

设置共享内存

int shmctl(int shmid, int cmd, struct shmid_ds *buf);
SHM_INFO

  1. int shmctl(int shmid, int cmd, struct shmid_ds *buf);
  2. struct shm_info {
  3. int used_ids; /* # of currently existing segments */
  4. unsigned long shm_tot; // Total number of shared memory pages
  5. unsigned long shm_rss; // # of resident shared memory pages
  6. unsigned long shm_swp; /* # of swapped shared memory pages */
  7. unsigned long swap_attempts;/* Unused since Linux 2.4 */
  8. unsigned long swap_successes;/* Unused since Linux 2.4 */
  9. };
  10. SHM_STAT // 设置
  11. SHM_LOCK // 上锁
  12. SHM_UNLOCK // 解锁

使用对象

链接 void _shmat(int shmid, const void _shmaddr, int shmflg);

**删除对象int shmdt(const void shmaddr);

  1. #include <sys/types.h>
  2. #include <sys/shm.h>
  3. void *shmat(int shmid, const void *shmaddr, int shmflg);
  4. SHM_RDONLY //
  5. SHM_REMAP //
  6. SHM_EXEC // 可执行方式

注意

1.父子进程的共享内存约定
fork函数 共享内存会自动取消
exec执行一个新的程序 自动卸载
exit 共享内存会自动取消

创建 读取 例:

  1. // 创建共享内存
  2. int shid=shmget((key_t)654321,(size_t)2048,0600|IPC_CREAT);
  3. // 链接到共享内存中
  4. void *sharem=shmat(shid,NULL,0);
  5. // 判断 共享内存中的数据是否为 end
  6. strcmp(sharem,"end");
  7. // 取消链接
  8. shmdt(sharem);

进行文件句柄的传输

对象

可以传递 有效数据 也可以传递控制数据

  1. #include<sys/socket.h>
  2. struct msghdr {
  3. void *msg_name; // 消息名
  4. socklen_t msg_namelen; /* size of address */
  5. struct iovec *msg_iov; // 用于传递 有效数据
  6. // 把数据合成一个数据来传递
  7. size_t msg_iovlen; // 有几个有效数据
  8. void *msg_control; // 用于传输 控制数据
  9. size_t msg_controllen; /* ancillary data buffer len */
  10. int msg_flags; /* flags on received message */
  11. };
  12. // 传输有效数据的结构体
  13. struct iovec { /* Scatter/gather array items */
  14. void *iov_base; //数据的头
  15. size_t iov_len; //数据的长度
  16. };
  17. // 传输控制数据的结构体
  18. struct cmsghdr {
  19. socklen_t cmsg_len; // 当前控制数据 有多少bit 包含头长度
  20. int cmsg_level; // 控制数据 级别
  21. int cmsg_type; // 数据类型 SCM_RIGHTS
  22. unsigned char cmsg_data[]; // 具体数据
  23. };

例:创建 连接

  1. #include<sys/un.h>
  2. int local_fd = socket(AF_LOCAL,SOCK_STREAM,0); // 创建本地套接字
  3. struct sockaddr_un myaddr; //创建御间套接字
  4. myaddr.sun_family = AF_LOCAL;// 协议类型
  5. // 这里省略创建文件 和 检测文件是否存在
  6. strncpy(myaddr.sun_path,"./file",strlen("./file")); //文件路径
  7. bind(local_fd,(struct sockaddr*)&myaddr,sizeof(myaddr)); // 绑定当前文件
  8. listen(local_fd,5); // 监听
  9. struct sockaddr_un peeraddr; //创建御间套接字
  10. int len = sizeof(myaddr);
  11. int nwe_fd = accept(local_fd,(struct sockaddr*)&peeraddr,&len); // 等待连接
  12. // 此连接也是使用 connect 函数连接
  13. // 但是注意 struct sockaddr_un 中的 sun_path 必须绑定同一个文件

例: 发送 链接数据

  1. int file_fd = open(file,|O_RDWR|O_APPEND); // 打开或者新建一个文件
  2. struct cmsghdr *cmsg; // 发送控制消息
  3. cmsg->cmsg_len = sizeof(struct cmsghdr) + sizeof(file_fd);//当前控制数据大小 当前头大小 + 控制数据大小
  4. cmsg->cmsg_level = SOL_SOCKET; // 控制数据 级别
  5. cmsg->cmsg_type = SCM_RIGHTS; // 发送数据 类型
  6. memcpy(CMSG_DATA(cmsg),&file_fd,sizeof(file_fd));
  7. // CMSG_DATA() 获取数据端地址
  8. // 选择 发送 有效数据
  9. struct msghdr msg;
  10. msg.msg_control = cmsg; // 控制数据地址
  11. msg.msg_controllen = cmsg->cmsg_len;// 控制数据长度
  12. struct iovec iov[1]; //存放 有效数据
  13. iov[0].iovbase = "hello";
  14. iov[0].iov_len = strlen("hello");
  15. msg.msg_iov = iov; // 有效数据首地址
  16. msg.msg_iovlen = 1; // 有效数据个数

sendmsg() 发送数据

recvmsg() 接收数据