2017-2018-1 20155222 《信息安全系统设计基础》第10周 Linux下的IPC机制
IPC机制
共享内存
共享内存头文件:
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/shm.h>
结构shmid_ds结构体(是不是很眼熟,看消息队列的msgid_ds结构体):
strcut shmid_ds{
struct ipc_perm shm_perm;
size_t shm_segsz;
time_t shm_atime;
time_t shm_dtime;
......
}
共享内存函数定义:
int shmget(key_t key,size_t size,int shmflg); //shmget函数用来创建一个新的共享内存段, 或者访问一个现有的共享内存段(不同进程只要key值相同即可访问同一共享内存段)。第一个参数key是ftok生成的键值,第二个参数size为共享内存的大小,第三个参数sem_flags是打开共享内存的方式。
eg.int shmid = shmget(key, 1024, IPC_CREATE | IPC_EXCL | 0666);//第三个参数参考消息队列int msgget(key_t key,int msgflag);
void *shmat(int shm_id,const void *shm_addr,int shmflg); //shmat函数通过shm_id将共享内存连接到进程的地址空间中。第二个参数可以由用户指定共享内存映射到进程空间的地址,shm_addr如果为0,则由内核试着查找一个未映射的区域。返回值为共享内存映射的地址。
eg.char *shms = (char *)shmat(shmid, 0, 0);//shmid由shmget获得
int shmdt(const void *shm_addr); //shmdt函数将共享内存从当前进程中分离。 参数为共享内存映射的地址。
eg.shmdt(shms);
int shmctl(int shm_id,int cmd,struct shmid_ds *buf);//shmctl函数是控制函数,使用方法和消息队列msgctl()函数调用完全类似。参数一shm_id是共享内存的句柄,cmd是向共享内存发送的命令,最后一个参数buf是向共享内存发送命令的参数。
管道
pipe函数原型:
#include <unistd.h>
int pipe(int file_descriptor[2]);//建立管道,该函数在数组上填上两个新的文件描述符后返回0,失败返回-1。
eg.int fd[2]
int result = pipe(fd);
命名管道(FIFO)
#include <sys/types.h>
#include <sys/stat.h>
int mkfifo(const char *filename,mode_t mode); //建立一个名字为filename的命名管道,参数mode为该文件的权限(mode%~umask),若成功则返回0,否则返回-1,错误原因存于errno中。
eg.mkfifo( "/tmp/cmd_pipe", S_IFIFO | 0666 );
int mknod(const char *path, mode_t mode, dev_t dev); //第一个参数表示你要创建的文件的名称,第二个参数表示文件类型,第三个参数表示该文件对应的设备文件的设备号。只有当文件类型为 S_IFCHR 或 S_IFBLK 的时候该文件才有设备号,创建普通文件时传入0即可。
eg.mknod(FIFO_FILE,S_IFIFO|0666,0);
信号 (signal)
#include <sys/types.h>
#include <signal.h>
void (*signal(int sig,void (*func)(int)))(int); //用于截取系统信号,第一个参数为信号,第二个参数为对此信号挂接用户自己的处理函数指针。返回值为以前信号处理程序的指针。
eg.int ret = signal(SIGSTOP, sig_handle);
int kill(pid_t pid,int sig); //kill函数向进程号为pid的进程发送信号,信号值为sig。当pid为0时,向当前系统的所有进程发送信号sig。
int raise(int sig);//向当前进程中自举一个信号sig, 即向当前进程发送信号。
#include <unistd.h>
unsigned int alarm(unsigned int seconds); //alarm()用来设置信号SIGALRM在经过参数seconds指定的秒数后传送给目前的进程。如果参数seconds为0,则之前设置的闹钟会被取消,并将剩下的时间返回。使用alarm函数的时候要注意alarm函数的覆盖性,即在一个进程中采用一次alarm函数则该进程之前的alarm函数将失效。
int pause(void); //使调用进程(或线程)睡眠状态,直到接收到信号,要么终止,或导致它调用一个信号捕获函数。
消息队列(Message queues)
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/msg.h>
struct msgbuf{
long mtype;
char mtext[1];//柔性数组
};
struct msgbuf{
long mtype;
char mtext[1];//柔性数组
};
define MSGMAX 8192
消息总的大小不能超过8192个字节,包括mtype成员(4个字节)。
2、msqid_ds内核数据结构
struct msgid_ds{
struct ipc_perm msg_perm;
time_t msg_stime;
time_t msg_rtime;
time_t msg_ctime;
unsigned long _msg_cbuyes;
..........
};
struct ipc_perm{
key_t key;
uid_t uid;
gid_t gid;
.......
};
key_t ftok( const char * fname, int id );//参数一为目录名称, 参数二为id。如指定文件的索引节点号为65538,换算成16进制为0x010002,而你指定的ID值为38,换算成16进制为0x26,则最后的key_t返回值为0x26010002。
eg.key_t key = key =ftok(".", 1);
int msgget(key_t key,int msgflag); //msgget用来创建和访问一个消息队列。程序必须提供一个键值来命名特定的消息队列。
eg.int msg_id = msgget(key, IPC_CREATE | IPC_EXCL | 0x0666);//根据关键字创建一个新的队列(IPC_CREATE),如果队列存在则出错(IPC_EXCL),拥有对文件的读写执行权限(0666)。
int msgsnd(int msgid,const void *msgptr,size_t msg_sz,int msgflg); //msgsnd函数允许我们把一条消息添加到消息队列中。msgptr只想准备发送消息的指针,指针结构体必须以一个长整型变量开始。
eg.struct msgmbuf{
int mtype;
char mtext[10];
};
struct msgmbuf msg_mbuf;
msg_mbuf.mtype = 10;//消息大小10字节
memcpy(msg_mbuf.mtext, "测试消息", sizeof("测试消息"));
int ret = msgsnd(msg_id, &msg_mbuf, sizeof("测试消息"), IPC_NOWAIT);
int msgrcv(int msgid, void *msgptr, size_t msg_sz, long int msgtype, int msgflg); //msgrcv可以通过msqid对指定消息队列进行接收操作。第二个参数为消息缓冲区变量地址,第三个参数为消息缓冲区结构大小,但是不包括mtype成员长度,第四个参数为mtype指定从队列中获取的消息类型。
eg.int ret = msgrcv(msg_id, &msg_mbuf, 10, 10, IPC_NOWAIT | MSG_NOERROR);
int msgctl(int msqid,int cmd,struct msqid_ds *buf); //msgctl函数主要是一些控制如删除消息队列等操作。 cmd值如下:
IPC_STAT:获取队列的msgid_ds结构,并把它存到buf指向的地址。
IPC_SET:将队列的msgid_ds设置为buf指向的msgid_ds。
IPC_RMID:内核删除消息队列,最后一项填NULL, 执行操作后,内核会把消息队列从系统中删除。