浅谈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.hsys/sem.hsys/shm.h
创建或打开IPCmsggetsemgetshmget
控制IPC操作函数mesgctlsemctlshmctl
IPC操作函数msgsnd/msgrcvsemopshmat/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, int cmd, .../*union semun arg */);
int shmctl(int shmid, int cmd, 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, size_t length, 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, struct sembuf *opsptr, size_t size)
{
    int ret = semop(semid, opsptr, size);
    if (ret == -1)
    {
        perror("semget:");
        exit(0);
    }
    return ret;
}

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值