概述
zeromq是一个非常简单使用的socket库,但是其使用方法又不同于通常意义上的socket,也和那些mq级的库也不同,这里主要以azmq为类来说明zeromq的使用方式。使用zeromq的时候理解其使用方式是最为重要的,这样才能融会贯通到自己的项目中去。本文主要讲述zeromq常用的使用方式。
REQ-REP
socket通信有个很原始的用法就是客户端请求,服务端回复,这个模式就是应对这种使用方式来而来的,客户端请求,服务端回复,双方严格遵守这个规则,zeromq通过一个状态机来维护这个状态,任何一方不遵守这个约定都会导致混乱。
服务端:
#include <azmq/socket.hpp> #include <boost/asio.hpp> #include <array> #include <glog/logging.h> #include <boost/make_shared.hpp> #include <boost/bind.hpp> #include <azmq/actor.hpp> namespace asio = boost::asio; /** * rep req模式的服务端 * @param argc * @param argv * @return */ int main(int argc, char **argv) { asio::io_service ios; azmq::rep_socket reponseSocket(ios); reponseSocket.bind("tcp://127.0.0.1:9999"); std::array<char, 2560 * 1000> buf; for (;;) { auto size = reponseSocket.receive(asio::buffer(buf)); LOG(INFO) << size << std::string(buf.data(), size); sleep(10); LOG(INFO) << "sta;rt send "; reponseSocket.send(asio::buffer(buf, size)); } }
客户端:
#include <azmq/socket.hpp> #include <boost/asio.hpp> #include <array> #include <glog/logging.h> namespace asio = boost::asio; int main(int argc, char **argv) { asio::io_service ios; azmq::req_socket reqSocket(ios); reqSocket.set_option(azmq::socket::snd_timeo(200)); reqSocket.set_option(azmq::socket::rcv_timeo(200)); reqSocket.connect("tcp://127.0.0.1:9999"); reqSocket.send(asio::buffer("hello")); std::array<char, 2560 * 1000> buf; auto size = reqSocket.receive(asio::buffer(buf)); LOG(INFO) << size; }
在通常的socket中,应对socket异常断开是个非常令人恶心的任务,但是在zeromq则是可以采用一种最为简单的办法来解决问题,设置发送延迟和接受延迟来解决snd_timeo rcv_timeo,客户端只要非常简单的设置超时,然后遇到错误重新创建socket然后在发送数据可,服务端能够自动适应这种情况。要注意的是zeromq本身并不在意客户端先启动还是服务端先启动。
PUB-SUB
在另外网络场景中是服务端要不停的主动发送数据到客户端,并不关心客户端是否连接。必然一些状态的数据,服务端会不停重复发送。
PUB端:
#include <azmq/socket.hpp> #include <boost/asio.hpp> #include <array> #include <glog/logging.h> namespace asio = boost::asio; int main() { asio::io_service ios; azmq::pub_socket pubSocket(ios); pubSocket.bind("tcp://127.0.0.1:10000"); for (int n = 0;; n++) { std::string text = "TESTMESSAGE" + std::to_string(n%10); LOG(INFO)<<text; pubSocket.send(asio::buffer(text)); sleep(1); } }
SUB端
#include <azmq/socket.hpp> #include <boost/asio.hpp> #include <array> #include <glog/logging.h> namespace asio = boost::asio; int main() { asio::io_service ios; azmq::sub_socket subSocket(ios); subSocket.connect("tcp://127.0.0.1:10000"); subSocket.set_option(azmq::socket::subscribe("TESTMESSAGE")); std::array<char, 2560 * 1000> buf; for (;;) { auto size = subSocket.receive(asio::buffer(buf)); LOG(INFO) << std::string(buf.data(), size); sleep(1); } }
注意客户端要调用 subSocket.set_option(azmq::socket::subscribe("TESTMESSAGE")); 方法订阅某个信息,这样当pub有信息来的时候就会收到对应的数据。当pub端停止的时候,sub端并没有任何异常,当pub上线之后sub端自动会接受到数据。
PUSH-PULL
有时当服务端要发布一些任务客户端处理,你肯定不会希望丢失某些任务信息,并能够按照客户端数量来平均的发送任务给客户端,那么你就应该使用这种方式。
push端
#include <azmq/socket.hpp> #include <boost/asio.hpp> #include <array> #include <glog/logging.h> #include <boost/make_shared.hpp> #include <boost/bind.hpp> #include <azmq/actor.hpp> namespace asio = boost::asio; int main() { asio::io_service ios; azmq::push_socket pushSocket(ios); pushSocket.bind("tcp://*:5557"); for (int n = 0;; n++) { std::string text = "pushSocket" + std::to_string(n%10); LOG(INFO)<<text; pushSocket.send(asio::buffer(text)); sleep(1); } }
pull端
#include <azmq/socket.hpp> #include <boost/asio.hpp> #include <array> #include <glog/logging.h> namespace asio = boost::asio; int main() { asio::io_service ios; azmq::pull_socket pullSocket(ios); pullSocket.connect("tcp://localhost:5557"); std::array<char, 2560 * 1000> buf; for (;;) { auto size = pullSocket.receive(asio::buffer(buf)); LOG(INFO) << std::string(buf.data(), size); sleep(1); } }
以上的代码均在https://github.com/onier/testAzmq.git
总结
使用zeromq重点在于根据自己的业务选择一种正确的socket模式。
来源:oschina
链接:https://my.oschina.net/u/3707404/blog/3210270