ZeroMQ 4.2.2 源代码分析 (二)

1. PUB & SUB模式

ZeroMQ 4.2.2 源代码分析 (二)_第1张图片

pub & sub模式的核心在于:

  • subscriber向publisher注册filter,
  • publisher根据filter向对应的subscriber发布消息。

ZeroMQ使用了两组socket_base_t的派生类。

xsub_t和sub_t用于sub端。sub_t的xsetsockopt()用于设置filter选项,它会调用xsub_t的xsend()向pub端发送一个注册请求。当sub端收到发布的消息时,会暂存在xsbub_t的fq_t成员中,以备以后用户调用xrecv()来获取。

xpub_t和pub_t用于pub端。 mtrie_t成员和dist_t成员配合使用,用于过滤和发布消息。mtrie_t是一种字典树,支持prefix match模式。sub端注册filter时,对应的pipe_t同时保存在mtrie_t和dist_t中,在mtrie_t中根据消息头(可以理解为topic)找到期望的目标pipe_t时,会调用mark_as_matching()在dist_t中标记pipe_t,然后dist_t根据标记发送消息。

2. 在Engine中的数据打包和解包(REVIEW)

ZeroMQ 4.2.2 源代码分析 (二)_第2张图片
  • 客户端和服务器的engine的交互分三个阶段:greeting,handshake和ready。engine自己完成greeting,接着它调用mechanism_t完成handshake,最后进入ready,可以开始真正的消息交互。
  • 进入ready时,如果socket要求,engine会发送一个identity消息给socket。socket是否要求由socket的options.recv_identity指定。一个要求identity的socket例子是router_t。
  • msg_t中的数据发送前需要转成ZMTP(ZeroMQ Message Transport Protocol)格式,接收后需要将ZMTP格式转回msg_t。engine调用encoder和decoder_t完成格式转换。i_encoder和i_decoder的不同派生类实现ZMTP的不同版本。

3. 在pipe_t中传送的消息格式

ZeroMQ 4.2.2 源代码分析 (二)_第3张图片

msg_t的union成员包含一个base或其派生类的成员。(这里的“派生”是指逻辑上的派生,实际上它们只是由同样的大小并共享部分成员,如type,flags)这些派生类的不同之处可能包括数据存储方式。如vsm将数据保存在结构内部,imsg将数据保存在用malloc额外分配的内存中。

base.type指定派生类的类型。base.flags则指定msg_t的其他特性,如msg_t::more可以将连续的一组msg_t组成一个multiple part的消息。又如:msg_t::command可以指定消息的类型是command而不是message。(ZeroMQ的消息有两种: command和message,command用于engine之间的数据交互,message是上层使用者(如pub和sub)的数据交互)

4. 在pub和sub间的数据交互

如下是sub和pub的数据交互的一个例子。ZMTP 3.1的完整语法定义见附录一。

Greeting阶段。pub端和sub端同时发送以下数据,由stream_engine自己完成。

0xFF 0x00...0x000 + x01 0x7F 0x03 0x01 NULL + 0x00...0x00 0x00...0x00
signature version major version minor mechanism(20 octets) Filler(32 octets)
  • 首先发送10 octets的signature。收到对端的signature后,认定对端也是ZMTP协议。
  • 然后发送1个octet的主版本号。收到对端的主板本号后,创建本地兼容的encoder/decoder。这里创建v2_encoder_t和v2_decoder_t。
  • 如果对端也是版本号3,则发送1 octet的次版本号,20 octet的mechanism名称,和一些填充字节。mechanism这里使用NULL,对应null_mechanism_t。收到对端的mechanism,确认是否与本地mechanism相同。是则greeting完成。

Handshake阶段。sub端发送如下数据:

0x04 + 0x16 0x05 + READY 0x0b + Socket-Type + 0x03 + SUB
1oct + 1 1 + 5 1 + 11 + 4 + 3
command-size (flag+length) command-name(length+name) command-data

pub端发送如下数据:

0x04 + 0x16 0x05 + READY 0x0b + Socket-Type + 0x03 + PUB
1oct + 1 1 + 5 1 + 11 + 4 + 3
command-size (flag+length) command-name(length+name) command-data
  • 首先是1 octet的长度标志: 1 octet的长度或8 octets的长度。然后是长度,这里是1 octet。这部分由encoder根据后面msg_t的数据添加。
  • 接着是command-body。包括command-name “READY”,和command-data “Socket-Type=PUB/SUB”。这部分来自msg_t的数据,由null_mechanism_t构造。
  • 注意command-data部分包括多组属性。每个属性包括:
    • 1 octet名字长度,
    • 名字,
    • 4 octets的值长度,
    • iv.值。
  • Pub和sub发送以上相应数据。收到对端数据后,则handshake完成。

ready阶段。sub端发送如下数据向pub端注册:

0x00 + 0x06 0x01 + topic
command-more/last (flag+length) message-body
  • 首先是1 octet的长度标志: 1 octet的长度或8 octets的长度。然后是长度,这里是1 octet。这部分由encoder根据后面msg_t的数据添加。
  • 接着是message-body。1 octet的注册/反注册标志。1是注册,0是反注册。Topic是注册的filter:”topic”,希望得到所有以”topic”开头的消息。

pub端发送如下数据,发布消息到sub端:

0x00 + 0x0C topic nm val
command-more/last (flag+length) message-body
  • 首先是1 octet的长度标志: 1 octet的长度或8 octets的长度。然后是长度,这里是1 octet。这部分由encoder根据后面msg_t的数据添加。
  • 接着是message-body。消息内容是”topic nm val”。

附录一 ZMTP 3.1 Grammar

The following ABNF grammar defines the protocol:

; The protocol consists of zero or more connections
zmtp = *connection

; A connection is a greeting, a handshake, and traffic
connection = greeting handshake traffic

; The greeting announces the protocol details
greeting = signature version mechanism as-server filler
signature = %xFF padding %x7F
padding = 8OCTET ; Not significant
version = version-major version-minor
version-major = %x03
version-minor = %x01

; The mechanism is a null padded string
mechanism = 20mechanism-char
mechanism-char = "A"-"Z" | DIGIT
| "-" | "_" | "." | "+" | %x0

; Is the peer acting as server for security handshake?
as-server = %x00 | %x01

; The filler extends the greeting to 64 octets
filler = 31%x00 ; 31 zero octets

; The handshake consists of at least one command
; The actual grammar depends on the security mechanism
handshake = 1*command

; Traffic consists of commands and messages intermixed
traffic = *(command | message)

; A command is a single long or short frame
command = command-size command-body
command-size = %x04 short-size | %x06 long-size
short-size = OCTET ; Body is 0 to 255 octets
long-size = 8OCTET ; Body is 0 to 2^63-1 octets
command-body = command-name command-data
command-name = short-size 1*255command-name-char
command-name-char = ALPHA
command-data = *OCTET

; A message is one or more frames
message = *message-more message-last
message-more = ( %x01 short-size | %x03 long-size ) message-body
message-last = ( %x00 short-size | %x02 long-size ) message-body
message-body = *OCTET

相关链接

ZeroMQ 4.2.2 源代码分析(一)
ZeroMQ 4.2.2 源代码分析(二)
ZeroMQ 4.2.2 源代码分析(三)
ZeroMQ 4.2.2 源代码(四)- Malamute

你可能感兴趣的:(ZeroMQ 4.2.2 源代码分析 (二))