简介
稍微偏底层的网络框架:
- 可以跨语言跨平台调用。
- 可以用
inproc
、IPC
、TCP
、TIPC
、multicast
多途径传递数据。 - 提供常用的模式,如
pub-sub(发布-订阅)
、push-pull(推送-拉取)
、router-dealer(路由器-经销商)
等模式。 - 快速的异步IO引擎。
- 开源、免费。
文档
- zeromq文档: http://zeromq.org/
- pyzmq学习文档:https://learning-0mq-with-pyzmq.readthedocs.io/en/latest/pyzmq/patterns/pair.html
- pyzmq api:https://pyzmq.readthedocs.io/en/latest/api/
常用api
Context
创建一个zmq的context。
Socekt
在context中创建一个socket。
socket.bind(addr)
让某个socket监听某个端口。其他socket想连接这个socket,需要使用socket.connect(addr)
。
socket.connect(addr)
通过端口地址,连接到远程的socket。
bind vs connect
- 服务端和客户端必须有
bind
和connect
,不能只用connect
。 - 不同的进程可以
connect
同一个端口,但不能bind
同一个端口。 - 必须要保证客户端先
connect
,服务端再发送数据,否则数据会丢失。 - 在实际传输数据之前,是客户端先调用
connect
还是服务端先调用bind
,这二者的顺序没有影响。
1 | import zmq |
常用模式
PAIR
传统soket:
- 点到点。
- 多对一(多个客服端,一个服务端)。
- 一对多(广播)。
PAIR
socket的行为类似于传统soket:
- 通讯是双向的。
- socket不保存特定状态。
- 只能连接一个(一对一,所以叫配对)
- 服务端监听一个特定的端口,一个客户端连接到上面。
1 | # 服务端 |
1 | client message to server1 |
客户端代码:
1 | port = "5557" |
客户端输出:
1 | Server message to client3 |
可以观察到:如果服务端绑定了bind
某个socket,需要在客户端连接connect
上这个socket以后,服务端传输的数据才能被客户端接收到,否则服务端发出去的数据会丢失。
注意:上面这点对于所有类型的socket都成立,必须要保证客户端先connect
,服务端再发送数据。另外,在实际传输数据之前,是客户端先调用connect
还是服务端先调用bind
,这二者的顺序没有影响。
Client / Server
又称Request/Reply
模式。
REQ
socket可以连接到多个服务端。- 请求可以被同时分发到多个服务端上。
REQ
在REP
返回消息之前,会被阻塞。REP
在REQ
返回消息之前,会被阻塞。
简单说必须你一言我一语。
1 | # 服务端 |
1 | Received request: Hello |
客户端代码:
1 | socket = context.socket(zmq.REQ) |
客户端输出:
1 | Sending request 0 ... |
可以观察到:每个REP
都会等待收到一个REQ
请求,然后才能继续发送响应;每个REQ
在发送请求后,必须等待收到一个REP
响应,才可以继续发送请求。
Publish/Subscribe
订阅/发布模式,就像微信上订阅公众号一样,你会收到所有你订阅的公众号发送的文章;同时每个公众号会把文章发给所有订阅这个公众号的用户。
1 | # 服务端 |
1 | 10000 -68 |
客户端代码:
1 | socket = context.socket(zmq.SUB) |
客户端输出:
1 | 9999 -76 |
Push/Pull
又称Pipeline
模式,很像生产者-消费者
模式。不一样的是,消费者的结果不会返回给上游,而是传给下游。
顺序:
- 启动结果管理器;
- 启动worker;
- 启动生产者。
1.启动结果管理器
1 | results_receiver = context.socket(zmq.PULL) |
2.启动worker
1 | import multiprocessing as mp |
1 | worker[0] stand by ... |
3.启动生产者,开始生产:
1 | # 生产端 |
worker端显示收到了数据。
结果管理器的输出:
1 | {'consumer': 0, 'num': 0} |