Linux-LPC通信
dup2 () 句柄重定向
会把第一个绑定的句柄关闭了 在重定向
popen() 获取进程句柄
运行一个命令 返回命令结果
FILE* finput = popen("echo -e texe!","r");read(fileno(finput),buf,100);
fileno() 获取此句柄
无名管道 pipe
简单传输速度快
- 无名管道 (pipe) :只有创建该管道的查询,才能找到该管道(亲缘进程管道)
- 如果 fork 一个新进程就必须 每一个进程都必须关闭一个 pipe的 fd
- 只能单向传输
- 如果对方 把 两个pipe fd 都关闭 当 要读写时 就会立马退出 并且收到 SIGPIPE信号
int pipe_fd[2];pipe(pipe_fd); //创建pipe 管道read(pipe_fd[0],buf,SIZ,0);//从管道中读取信息close(pipe_fd[1]); //关闭 一个pipe
有名管道 fifo
没有办法实现双向通信 传输速度慢
- FIFO 是依赖于文件系统
和普通文件一样 拥有文件权限和其他属性,所有程序都可以通过fifo 的fd来找到有名管道
- 命令行创建一个 有名管道
mknod FIFOTEST p- p 代表管道文件
- fifo 必须 两端都同时打开 fifo 是 才能写进管道 否则就会阻塞 等待 其他进程打开
int ret = mkfifo(./file.tmp,0666|S_IFIFO);//创建 fifo 管道文件int fd = open(./file.tmp,O_WRONLY|O_CREAT|0644);//打开 fifo管道
- fifo 是一个文件,存储信息在内存中
- 只能单向通信
- 只能进行少量数据传输
- 只能一对一传输
- 两个进程,中途退出一个进程,未退出的一段如果是写操作的话,返回sigpipe信息
- 未退出的一端如果是阻塞读操作的话,该操作不会继续阻塞,而直接返回0
system v ipc XSI消息队列
system v 和 ipc 共同的结构体
struct msqid_ds
struct msqid_ds { // 消息结构体链表struct ipc_perm msg_perm; // 描述当前 msg 的权限time_t msg_stime; // 最后发送时间time_t msg_rtime; // 最后接收时间time_t msg_ctime; // 最后改变时间unsigned long __msg_cbytes; // 消息的字节数msgqnum_t msg_qnum; // 消息的个数msglen_t msg_qbytes; // 最大的字节数pid_t msg_lspid; // 最后一个发送进程的PIDpid_t msg_lrpid; // 最后一个接收的进程的PIDstruct msg * msq_first ; // 头指针struct msg * msq_last ; // 尾指针};
- 拥有者及权限对象
struct ipc_perm
struct ipc_perm{__kernel_key_t key;// 当前的 key__kernel_uid_t uid;//用户id__kernel_gid_t gid;//组id__kernel_uid_t cuid;//当前用户id__kernel_gid_t cgid;//当前组id__kernel_mode_t mode; // 属性类型 读 写 属性unsigned short seq;};
优点和缺点
优点:
1. 消息队列是两个不相关进程之间传递数据的有效渠道.
2. 与命名管道相比,具有的优势是:
独立于发送以及接收进程而存在;
消除命名管道的打开以及关闭而存在的困难;
可以提前查看紧急信息;
避免命名管道的同步以及阻塞问题;
缺点:
与命名管道一样,每个数据块都有一个最大
度限制;系统中所有队列包含的全部数据块长度也有一个上限;
- 创建key
- key :通信双方约定好的值,32位的整形数据
- id :系统会为IPC分配一个唯一的ID,通信双方都需要知道ID才能使用当前IPC方法,创建者会返回当前ID值,
- 使用命令 lpcs 可以查看所有 共享内存的字段
#include <sys/types.h>#include <sys/ipc.h>key_t ftok(const char *pathname, int proj_id);pathname: 路径proj_idkey 31-24 proj_id 低8位key 23-16 st_dev属性的低8位key 15-0 st_ino属性的低16位;
- 创建对象:
int msgget(key_t key, int msgflg);
#include <sys/types.h>#include <sys/ipc.h>#include <sys/msg.h>int msgget(key_t key, int msgflg);参数1: key_t key参数2:int msgflg 确定消息队列的访问权限,IPC_CREAT 找到当前的key对应的IPC,如果没有IPC则进行创建IPC_EXCL 如果存在则返回失败IPC_NOWAIT 返回值为当前ipc对应的id值;msgget(key,0600|IPC_CREAT);
- 设置对象:
int msgctl(int msqid,int cmd,struct msqid_ds *buf);cmd:IPC_RMID 删除IPC_SET 设置ipc_perm参数IPC_STAT 获取ipc_perm参数IPC_INFO 获取ipc信息 和ipc
- 使用对象:
- 发送
int msgsnd(int msqid,const void *msg_ptr,size_t sz,int msgflg);
参数 sz:只是发送数据的长度 而不是全结构体长度
msqid : 是 msgget的返回值 用于发送struct msgbuf{long mtype; // 发送消息的类型char mtext[1]; // 发送的数据
- 发送
- 接收
- ssizet msgrcv(int msqid, void _msgp, size_t msgsz, long msgtyp,int msgflg);
ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp,int msgflg);msqid: 从哪一个 消息队列中收;msgp: 收取存放的结构体;msgsz:收取的大小;msgtyp:收取的类型
msgtyp 0 默认接收第一条消息
msgtyp > 0 接收第一条msgtyp消息
msgtyp < 0 接收小于msgtyp绝对值的消息
XSL信号量
概念:
- 实现进程间同步
- 表示系统可用资源的个数
对象:
struct semid_ds {struct ipc_perm sem_perm; //和IPC权限一样time_t sem_otime;//最后一次调用信号操作的时间time_t sem_ctime; // 最后一次信号改变的时间unsigned long sem_nsems; //信号的个数struct sem * sem_base;// 单向指针 指向信号头节点};struct sem{int semval // 信号量的值int sempid // 最近一个操作的进程号}
对象操作
- 创建对象: 创建信号对象
int semget(key_t k,int n,int semflag);
#include <sys/ipc.h>#include <sys/sem.h>int semget(key_t key, int nsems, int semflg);nsems:创建信号的个数semflg:权限 IPC_CREAT
- 设置对象:
int semctl(int sid,int semnum,int cmd,union semun a);
int semctl(int sid,int semnum,int cmd,union semun a);union semun {int val; /* 信号的值 */struct semid_ds *buf; /* Buffer for IPC_STAT, IPC_SET */unsigned short* array; /* Array for GETALL, SETALL */struct seminfo *__buf; /* Buffer for IPC_INFO*/};cmd 如果对于整个信号量集合,则有如下设置方法IPC_STAT ipc_permIPC_SET ipc_permIPC_RMIDIPC_INFO 信号量的系统信息cmd 如果对于单个信号量集合,则有如下设置方法GETPID 获取信号拥有者的PIDsemnum:参数无效GETVAL 获取信号的值 并且返回信号的值semnum:获取第几个信号的值GETALL 获取所有信号的值semnum:0semun: 存储信号的地址SETVAL 设置某一个信号的值semnum:设置第几个信号的值semun: 设置的值SETALL 设置所有信号的值semnum:0semun: 设置的值
- 使用对象
int semop(int s,struct sembuf *sb,size _t n);s:操作信号的id;n:第几个信号struct sembuf{unsigned short int sem_num; //信号的值short int sem_op; //选项short int sem_flg; //权限// sem_flg 的值为 SEM_UNDO 时 当当前进程退出时 撤回当前进程使用的所有资源};sem_op:的值+ 表示进行加- 表示进行减
XSI共享内存
- 数据量最大
- 传输最快
- mmap
共享内存对象
struct shmid_ds {struct ipc_perm shm_perm; /* operation perms */int shm_segsz; /* size of segment (bytes) */__kernel_time_t shm_atime; /* last attach time */__kernel_time_t shm_dtime; /* last detach time */__kernel_time_t shm_ctime; /* last change time */__kernel_ipc_pid_t shm_cpid; /* pid of creator */__kernel_ipc_pid_t shm_lpid; /* pid of last operator */unsigned short shm_nattch; /* no. of current attaches */}
创建共享内存
int shmget(key_t key, size_t size, int shmflg);
共享内存的权限
#include <sys/ipc.h>#include <sys/shm.h>int shmget(key_t key, size_t size, int shmflg);shmflg:权限SHM_RSHM_W
设置共享内存
int shmctl(int shmid, int cmd, struct shmid_ds *buf);
SHM_INFO
int shmctl(int shmid, int cmd, struct shmid_ds *buf);struct shm_info {int used_ids; /* # of currently existing segments */unsigned long shm_tot; // Total number of shared memory pagesunsigned long shm_rss; // # of resident shared memory pagesunsigned long shm_swp; /* # of swapped shared memory pages */unsigned long swap_attempts;/* Unused since Linux 2.4 */unsigned long swap_successes;/* Unused since Linux 2.4 */};SHM_STAT // 设置SHM_LOCK // 上锁SHM_UNLOCK // 解锁
使用对象
链接 void _shmat(int shmid, const void _shmaddr, int shmflg);
**删除对象int shmdt(const void shmaddr);
#include <sys/types.h>#include <sys/shm.h>void *shmat(int shmid, const void *shmaddr, int shmflg);SHM_RDONLY //SHM_REMAP //SHM_EXEC // 可执行方式
注意
1.父子进程的共享内存约定
fork函数 共享内存会自动取消
exec执行一个新的程序 自动卸载
exit 共享内存会自动取消
创建 读取 例:
// 创建共享内存int shid=shmget((key_t)654321,(size_t)2048,0600|IPC_CREAT);// 链接到共享内存中void *sharem=shmat(shid,NULL,0);// 判断 共享内存中的数据是否为 endstrcmp(sharem,"end");// 取消链接shmdt(sharem);
进行文件句柄的传输
对象
可以传递 有效数据 也可以传递控制数据
#include<sys/socket.h>struct msghdr {void *msg_name; // 消息名socklen_t msg_namelen; /* size of address */struct iovec *msg_iov; // 用于传递 有效数据// 把数据合成一个数据来传递size_t msg_iovlen; // 有几个有效数据void *msg_control; // 用于传输 控制数据size_t msg_controllen; /* ancillary data buffer len */int msg_flags; /* flags on received message */};// 传输有效数据的结构体struct iovec { /* Scatter/gather array items */void *iov_base; //数据的头size_t iov_len; //数据的长度};// 传输控制数据的结构体struct cmsghdr {socklen_t cmsg_len; // 当前控制数据 有多少bit 包含头长度int cmsg_level; // 控制数据 级别int cmsg_type; // 数据类型 SCM_RIGHTSunsigned char cmsg_data[]; // 具体数据};
例:创建 连接
#include<sys/un.h>int local_fd = socket(AF_LOCAL,SOCK_STREAM,0); // 创建本地套接字struct sockaddr_un myaddr; //创建御间套接字myaddr.sun_family = AF_LOCAL;// 协议类型// 这里省略创建文件 和 检测文件是否存在strncpy(myaddr.sun_path,"./file",strlen("./file")); //文件路径bind(local_fd,(struct sockaddr*)&myaddr,sizeof(myaddr)); // 绑定当前文件listen(local_fd,5); // 监听struct sockaddr_un peeraddr; //创建御间套接字int len = sizeof(myaddr);int nwe_fd = accept(local_fd,(struct sockaddr*)&peeraddr,&len); // 等待连接// 此连接也是使用 connect 函数连接// 但是注意 struct sockaddr_un 中的 sun_path 必须绑定同一个文件
例: 发送 链接数据
int file_fd = open(file,|O_RDWR|O_APPEND); // 打开或者新建一个文件struct cmsghdr *cmsg; // 发送控制消息cmsg->cmsg_len = sizeof(struct cmsghdr) + sizeof(file_fd);//当前控制数据大小 当前头大小 + 控制数据大小cmsg->cmsg_level = SOL_SOCKET; // 控制数据 级别cmsg->cmsg_type = SCM_RIGHTS; // 发送数据 类型memcpy(CMSG_DATA(cmsg),&file_fd,sizeof(file_fd));// CMSG_DATA() 获取数据端地址// 选择 发送 有效数据struct msghdr msg;msg.msg_control = cmsg; // 控制数据地址msg.msg_controllen = cmsg->cmsg_len;// 控制数据长度struct iovec iov[1]; //存放 有效数据iov[0].iovbase = "hello";iov[0].iov_len = strlen("hello");msg.msg_iov = iov; // 有效数据首地址msg.msg_iovlen = 1; // 有效数据个数
