从零自制docker-3-【IPC Namespace】(System V IPC和POSIX IPC Namespace cmd.Run() 啥是消息队列 消息队列相关结构 ipcs -q ipc)

本文通过餐馆订单处理的比喻,对比SystemVIPC和POSIX消息队列的异同,讨论了它们的命名、访问方式、优先级和API特性。同时介绍了IPCNamespace的概念,以及如何在代码中使用`cmd.Run()`和消息队列的相关结构,如key_t、msqid和ipcs命令的使用。
摘要由CSDN通过智能技术生成

System V IPC和POSIX

让我们通过一个简单的餐馆订单处理的比喻来理解System V IPC和POSIX消息队列及它们之间的区别。

假设一个餐馆有前厨和后厨,前厨负责接收顾客的订单,然后需要将订单传递给后厨以便烹饪。

System V IPC 消息队列

System V IPC相当于使用一种特殊的订单系统。在这个系统中:

  • 前厨写下订单并给每个订单一个指定的类型标签,比如“前菜”,“主菜”,“甜点”等。
  • 后厨有一个列表,里面有所有的订单类型。
    后厨可以选择查看特定类型的订单,比如说现在后厨只想看“主菜”的订单。
  • 这些订单被放在一个特殊的柜台上,后厨工作人员必须按照特定的规则来检查柜台,比如使用特殊的钥匙。(这里的“钥匙”指的是System V IPC消息队列中的键值 key_t)
  • 订单一旦被写下,即便前厨的工作人员离开了,订单也会留在柜台上,直到后厨的人显式地处理它。

POSIX 消息队列

而如果这家餐馆使用POSIX消息队列来处理订单:

  • 前厨使用一个更现代的系统来写订单,每个订单都可以标记一个紧急级别。
  • 后厨有一个显示器,它会自动将最紧急的订单排在最前面。
  • 后厨可以一直查看这个显示器,并按紧急程度的先后顺序取出订单。
  • 显示器还有一个灯光提示,如果后厨太忙没时间看,灯光会告诉他们是否有新的订单等待处理。(这里的“灯光提示”可以想象成 POSIX 消息队列的非阻塞特性)
  • 一旦某个订单完成,显示器自动更新,不需要特殊的钥匙或操作。
    区别

现在来总结一下它们之间的主要区别:

  • 名称和访问方式:SysV IPC 使用一个整数键值(key_t)来访问消息队列,这需要一种特殊的方法来生成和获取键值。而POSIX消息队列像文件一样,通过一个字符串名字来访问,这就使得它看起来更像是操作系统的一部分而不是一个单独的服务。
  • 消息优先级:POSIX允许对消息进行优先级排序,这样可以确保最重要的消息首先被处理。SysV的消息队列也可以实现类似的功能,但通常不那么直观或简单。
  • 接口和功能:POSIX API通常被认为更现代、更一致,有更好的错误处理和更完整的功能集合。SysV IPC在某些操作系统的某些版本中可能不那么直观或者不那么可靠。

这些区别使得在新的系统或者需要更多功能的场景下,POSIX消息队列可能是更好的选择,而SysV IPC可能在旧系统中因为兼容性而被使用。

IPC Namespace

想象一下,进程间通信(IPC)就像一个邮局系统。这个系统内,城市里的居民(各个进程)想要发送信件或包裹(数据)给对方。为了完成这项任务,他们会用到邮局提供的服务,比如信箱、包裹传送带、或者邮递员(这些对应于IPC的通信方式,如消息队列、信号量、共享内存等)。

现在,来到“ipcnamespace”。这个词可以被理解为独立的小社区或者小分区。每个小社区内,居民有自己的小邮局,他们自己的信箱和包裹传送带。社区外的人是不能直接使用别的社区的信箱和邮局服务的。这样一来,每个社区内的通信都是独立和私密的。

在计算机中,IPC namespaces起到了类似的作用。当你创建了一个新的IPC namespace后,你实际上是在现有的操作系统中创建了一个隔离的小社区,进程可以在这个小区内自由地传递信息,而外面的进程则不能干预。这在你不想让某些程序受到外界影响的时候特别有用,比如在使用Docker这样的容器技术来隔离和管理不同应用程序时。每个容器都运行在它自己的IPC namespace中,确保了内部进程通信的独立性和安全性。这就像给应用程序提供了一个“私人邮局”,只服务于容器内部,互不影响。

cmd.Run()

cmd.Run()方法在命令成功执行完成时返回nil(没有错误),如果有错误发生(如命令找不到、执行时出错),则返回error类型的值。

啥是消息队列

消息队列是一种进程间通信(IPC)或应用程序间通信(介于不同应用程序或服务之间)的方法,它允许进程通过读/写入队列进行通信,而无需直接相互知晓。队列是消息的有序集合,这些消息可以是数据、命令或者任何可以转换为字节串的信息。

消息队列的工作原理类似于现实生活中的邮局系统:

  • 发送消息(发送信件): 一个进程(或线程)作为消息的发送者(像人们发送信件一样),将消息放入到一个消息队列中。

  • 存储消息(邮局保管信件): 队列临时存储这些信息,直到接收者准备好接收它们。消息队列能保证消息的顺序,并且确保消息不会丢失。

  • 接收消息(收取信件): 另一个进程(或线程)作为消息的接收者,从队列中按顺序取出消息进行处理。

消息队列相关结构

消息队列的基本结构很简单,但至关重要,能够有效地协调消息的生产者(发送方)和消费者(接收方)。以下是消息队列的一些主要组成部分:

  • 消息: 消息是消息队列结构中基本的数据单位。它可以包含任意形式的数据,如字符串、对象或字节流。通常,消息由两部分组成:消息头(包含元数据,如消息ID、时间戳、优先级等)和消息体(包含实际发送的数据)。

  • 队列: 队列是一个有序的消息集合,它按照先入先出(FIFO)的原则操作。也就是说,最先发送到队列的消息将是最先被接收处理的。队列在消息的生产者和消费者之间提供了一个缓冲区,允许他们在不同的速率下工作。

  • 生产者(发送方): 生产者是创建和发送消息至队列的实体。生产者将消息发送到队列,并且一旦发送完成,它通常不再关心消息是否被消费。

  • 消费者(接收方): 消费者从队列中读取和处理消息。消费者可以是直接监听队列的进程,当消息到达时立即处理,也可以是定期检查新消息的进程。在某些情况下,消费者处理完消息后会发送一个响应或者结果。

ipcs -q

ipcs命令是Linux操作系统中用于报告Inter-Process Communication (IPC)设施的状态的一个工具。ipc代表进程间通信,它可以包括消息队列、信号量和共享内存段等。ipcs命令能够显示每种类型IPC对象的当前状态,这对于诊断或系统监控很有用。

当ipcs命令与-q选项一起使用时(即ipcs -q),它将专门报告关于消息队列的信息。输出将包括每个消息队列的key、msqid以及其他附加信息。

这里是一个ipcs -q命令的典型输出示例:

------ Message Queues --------
key        msqid      owner      perms      used-bytes   messages    
0x12345678 0          myuser     644        0            0           
0xaabbccdd 1          anotherusr 644        16384        4
 

解释一下以上示例中每一列代表的意义:

  • key:用于唯一标识消息队列的键值。
  • msqid:消息队列的内核内部唯一标识符。
  • owner:创建消息队列的用户。
  • perms:消息队列的权限,通常以八进制形式显示。
  • used-bytes:当前在队列中的所有消息占用的总字节数。
  • messages:当前在队列中的消息数量。

ipcmk -Q

ipcmk是Linux下用来创建IPC(Inter-Process Communication)资源的命令,它可以创建消息队列、共享内存以及信号量。当你使用ipcmk -Q(请注意,参数Q是大写的),它将创建一个新的消息队列。

这里是ipcmk -Q的简单用法及输出:

$ ipcmk -Q
Message queue id: 32768
 

在这个例子中,ipcmk -Q命令创建了一个新的消息队列,并输出它的消息队列ID(msqid)。这个ID是用来访问和管理消息队列的关键标识。如果需要在你的程序中使用这个消息队列,你将需要这个ID。

msqid 和key的区别

想象一下我们有一个邮局,邮局里有许多邮箱,每个邮箱都有一个独一无二的邮箱号码(这就像是msqid)。如果你想放一封信进某个邮箱,你就需要知道那个邮箱的号码。

但是,要得到一个邮箱号码,你需要先告诉邮局一个密码或者代码,这样他们就能根据这个密码分配一个邮箱给你(这个密码就像是key)。这个密码有可能是共享的,也就是说,其他人也可能知道这个密码,并用它来请求同样的邮箱号码。

比方说,一个学校想要设立一个信息发布系统,他们决定使用一个消息队列来发布通知,并且他们选择使用学校的识别码“123”和一个特定的项目标识符’A’生成这个key。

首先,他们为此生成一个key:

// 学校使用识别码(例如123)和项目标识符(例如 'A')生成key
key_t key = ftok("/path/to/somefile", 'A');  

得到这个key后,学校可以用它来获取它们自己的邮箱号码(msqid):


// 学校通过提供key来请求(如果不存在,则创建)一个邮箱号码(msqid)
int msqid = msgget(key, IPC_CREAT | 0666); 
 

如果请求成功,邮局(操作系统)会分配一个独一无二的邮箱号码(msqid)给学校的信息发布系统。

这时,学校的信息发布部门就可以通过这个邮箱号码(msqid)来发送通知,而其他学校的部门或者服务如果知道这个邮箱号码,也可以到"邮局"拿这个邮箱号码来接收通知。他们不需要知道最开始的密码(key);只要他们有邮箱号码(msqid),他们就可以访问那个邮箱(消息队列)。

代码

相比之前只是Cloneflags:CLONE_NEWUTS|CLONE_NEWIPC不同而已

package main

import
(
	
	"os/exec"
	"syscall"
	"os"
	"log"
)
func main(){
	cmd:=exec.Command("sh")
	cmd.SysProcAttr = &syscall.SysProcAttr{
		Cloneflags: syscall.CLONE_NEWUTS | syscall.CLONE_NEWIPC ,
	}
	cmd.Stdin=os.Stdin
	cmd.Stdout=os.Stdout
	cmd.Stderr=os.Stderr

	if err:=cmd.Run();err!=nil{
		log.Fatal(err)
	}
}

演示

在这里插入图片描述

  • 26
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

看星猩的柴狗

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值