浅谈UNIX网络编程system V IPC机制

前端之家收集整理的这篇文章主要介绍了浅谈UNIX网络编程system V IPC机制前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。

进程间通信(IPC,Inter-Process Communication)指至少两个进程或线程间传送数据或信号的一些技术或方法

一.System V IPC 的构成

    1.system v消息队列

    2.system v信号量

    3.system v共享内存

我们把这三种工具统称为System V IPC的对象,每个对象都具有一个唯一的IPC标识符(identifier)。要保证不同的进程能够获取同一个IPC对象,必须提供一个IPC关键字(IPC key),内核负责把IPC关键字转换成IPC标识符。
汇总 消息队列 信号量 共享内存区|
文件 sys/msg.h sys/sem.h sys/shm.h
创建或打开IPC msgget semget shmget
控制IPC操作函数 mesgctl semctl shmctl
IPC操作函数 msgsnd/msgrcv semop shmat/shmdt

**

二.Ftok函数

**

    系统建立IPC通讯(如消息队列、共享内存时)必须指定一个ID值。通常情况下,该id值通过ftok函数得到。


ftok原型如下:
            **key_t ftok( char * fname,int id )**
            fname就时你指定的文件名(该文件必须是存在而且可以访问的),**id是子序号,虽然为int,但是只有8个比特被使用(0-255)。**
            当成功执行的时候,一个key_t值将会被返回,否则 -1 被返回。在一般的UNIX实现中,是将文件的索引节点号取出,前面加上子序号得到key_t的返回值。如指定文件的索引节点号为65538,换算成16进制为 0x010002,而你指定的ID值为38,换算成16进制为0x26,则最后的key_t返回值为0x26010002。

三.创建与打开IPC通道


对于key值,应用程序可以有两种选择
1.调用ftok,给它传递pathname和id。
2.指定key为IPC_PRIVATE,这将保证会创建一个新的唯一的IPC对象(不推荐)。

四.创建通道-getXXX函数

通常我们使用getxxx函数来创建或者访问一个已知的通道。

int msgget(key_t key,int flag);
int semget(key_t key,int nsems,int flag);
int shmget(key_t key,size_t size,int flag);

这个函数都有一个flag参数(由逻辑或组成),该参数也可类比open函数的flag参数,虽然取值不尽相同。这三个函数的flag取值是一样的。

IPC_CREAT    如果key不存在,则创建(类似open函数的O_CREAT)
IPC_EXCL       如果key存在,则返回失败(类似open函数的O_EXCL)
IPC_NOWAIT  如果需要等待,则直接返回错误

用一个图表更能体现其中的逻辑

oflag参数 key不存在 key存在
无特殊标志 出错,errno = ENOENT 成功,引用已存在的对象
IPC_CREAT 成功,创建新对象 成功,引用新对象
IPC_CREAT|IPC_EXCL 成功,创建新对象 出错,errno = EEXIST

另外oflag中的参数也将初始化ipc_perm结构中的mode成员。其中权限有一个简单的记忆方法,就是和linux中的权限是一样的,比如说你给一个0644系统将识别为MSG_R|MSG_W|MSG_R>>3|MSG_R>>6

五.控制函数——xxxctl函数

int msgctl(int msqid,int cmd,struct msqid_ds *buf);
int semctl(int semid,int semmun,.../*union semun arg */);
int shmctl(int shmid,struct shmid_ds *buf);

三个ctl控制函数其实是在操作三种IPC机制对应的三种数据结构:

msqid_ds
semid_ds
shmid_ds

它们有共同的后缀——id_ds。ds就是data structure(数据结构)的意思。
此处要注意的是消息队列的对应的结构体名称,其前缀为msq而非msg(这个缩写有点违和,取了队列的首字母q)
这些结构体中有一个共同的成员就是前面提到的ipc_perm。。
这三个函数都有一个cmd参数(控制参数),不同的IPC机制它们的控制参数是不一样的。但是由几个控制参数是公共的(定义在ipc.h中)。下面以消息队列为例(也适用于信号量和共享内存)

命令 功能
IPC_RMID 删除消息队列。只能由其创建者或超级用户(root)来删除
IPC_SET 设置消息队列的属性。按照buf指向的结构中的值,来设置此IPC对象
IPC_STAT 读取消息队列的属性。取得此队列的msqid_ds结构,并存放在buf中

semctl函数有更复杂的作用,我们在稍后再谈。

五.操作函数

操作函数在不同的体系中有着不一样的作用。
在消息队列中

int msgsnd(int msqid,const void *ptr,size_t length,int flag);
ssize_t msgrcv(int msqid,void *ptr,long type,int flag);

其中 ptr所指向的结构需要自己构造,通常是这样

struct msgbuf
{
    long mtype;
    char mtetx[MAX_LINE];
}

在msgsnd中 size_t 应该为发送的mtetx的长度可以用strlen(mtetx)+1
在msgrcb中 size_t 应该为ptr所指向的缓冲区的数据部分大小,是函数可以返回的最大数据量,可以用MAX_LIEN

在信号量中

int semop(int semid,struct sembuf *opsptr,size_t nops);

opsptr指向sembuf

struct sembuf
{
    short sem_num;   
    short sem_op;
    short sem_flag;
}

用于操作信号集中sem_num的信号量的增减,增减量由sem_op来决定。

在共享内存区中

int shmdt(const void *shmaddr);
void *shmat(int shmid,const void *shmaddr,int flag);

shmat函数是将共享内存区链接调用的进程空。
其中当shmaddr 为NULL,系统替调用者选择地址(推荐)
当为一个非空的指针的时候,返回的地址取决与flag中的SHM_RND。没有指定者直接附接到shmaddr的地址上,指定了则附接到shmaddr向下舍入SHMLBA的常值所指向的地址上。
shmdt函数用于断接shmat附接的内存区。

六.小技巧-包裹函数

在UNIX网络编程中常常出现一些首字符大写的函数,这些是包裹函数,包裹了出错处理。有些函数不止。
这是我自己写的包裹函数,可以参考一下。

int Semop(int semid,size_t size)
{
    int ret = semop(semid,opsptr,size);
    if (ret == -1)
    {
        perror("semget:");
        exit(0);
    }
    return ret;
}

这样可以大量节省编程时间和代码量。

原文链接:https://www.f2er.com/bash/389844.html

猜你在找的Bash相关文章