学了saltstack有一段时间了,说实话,对于一个python爱好者来说salt源代码真是一个宝藏啊。于是乎去看了源代码,发现所有问题都卡在了底层通信上,在看saltstack之前都不知道有一个这么好的zeromq通信协议。现在就来记录关于zeromq的学习笔记。


zmq是什么:zmq是基于之前协议(tcp,ipc,inproc)开发的并发框架,采用异步IO非阻塞方式,多对多的通信模式,无需在意服务端和客户端的启动顺序。它包含四种通信模式:PAIR/PAIR,REP/REQ,PUB/SUB,PUSH/PULL。其他模式都是基于这四种混合使用的。


PAIR/PAIR:一对一的请求,跟普通socket类似,这种模式一般不会用。

了解saltstack的通信协议zeromq(一)_第1张图片

代码如下:

server.py

import zmq
import random
import sys
import time

port = "5556"
context = zmq.Context()
socket = context.socket(zmq.PAIR)
socket.bind("tcp://*:%s" % port)

while True:
        socket.send("Server message to client3")
        msg = socket.recv()
        if msg == 'EOF':
                break
        print msg
        time.sleep(1)

client.py

import zmq
import random
import sys
import time

port = "5556"
context = zmq.Context()
socket = context.socket(zmq.PAIR)
socket.connect("tcp://localhost:%s" % port)

for i in range(5):
        msg = socket.recv()
        print msg
        socket.send("client message to server1")
        time.sleep(1)
socket.send("EOF")

zmq有个好处,就是无需在意server和client的启动顺序。执行这两个脚本。


REP/REQ:请求应答模式,是多对多模式,这个模式必须遵循一定的顺序,且recv和send是成对存在的。客户端首先必须send一个请求再recv响应,服务端必须recv一个请求再send响应。这种模式可以用于负载均衡。

了解saltstack的通信协议zeromq(一)_第2张图片

reqrep_server.py

import zmq
import time
import sys

port = "5556"
if len(sys.argv) > 1:
        port =  sys.argv[1]
        int(port)

context = zmq.Context()
socket = context.socket(zmq.REP)
socket.bind("tcp://*:%s" % port)

while True:
        #  Wait for next request from client
        try:
                message = socket.recv()
                print "Received request: ", message
                time.sleep (1)  
                socket.send("World from %s:%s" % ('192.168.79.49',port))
        except KeyboardInterrupt:
                break

repreq_client.py

import zmq
import sys

port = "5556"
if len(sys.argv) > 1:
        port =  sys.argv[1]
        int(port)

if len(sys.argv) > 2:
        port1 =  sys.argv[2]
        int(port1)

context = zmq.Context()
print "Connecting to server..."
socket = context.socket(zmq.REQ)
socket.connect ("tcp://localhost:%s" % port)
if len(sys.argv) > 2:
        socket.connect ("tcp://localhost:%s" % port1)

for request in range (1,10):
        print "Sending request ", request,"..."
        socket.send ("Hello")
        #  Get the reply.
        message = socket.recv()
        print "Received reply ", request, "[", message, "]"

python reqrep_server.py 5555

python reqrep_server.py 5556

python reqrep_client.py 5555 5556

执行这三个命令,请求会均衡的发到两个服务端。