1.zmq_ageng.hpp
#ifndef SRC_ZMQ_AGENT_HPP_
#define SRC_ZMQ_AGENT_HPP_
#include <string.h>
#include <string>
#include <map>
#include <zmq.h>
namespace zmq_self_agent {
enum socket_style {
BIND,
CONNECT
};
enum socket_error {
NO_ERROR,
CONTEXT_ERROR,
SOCKET_ERROR,
SOCKET_TYPE_ERROR,
BIND_ERROR,
CONNECT_ERROR,
SOCKET_ATTRIBUTE_ERROR
};
enum socket_type {
PUB_STYPLE = ZMQ_PUB,
SUB_STYPLE = ZMQ_SUB,
PUSH_STYPLE = ZMQ_PUSH,
PULL_STYPLE = ZMQ_PULL
};
class zmq_config {
public:
zmq_config() {
sock_type = 0;
addr = nullptr;
send_hwm = 1000;
recv_hwm = 1000;
send_timeout = 5;
}
public:
unsigned char sock_type;
const char *addr;
int send_hwm;
int recv_hwm;
int send_timeout;
std::string topic; // for pub/sub
};
class zmq_agent {
public:
zmq_agent() {
context_ = nullptr;
socket_ = nullptr;
init_map();
}
virtual ~zmq_agent() {
if (nullptr != socket_) {
zmq_close(socket_);
socket_= nullptr;
}
if (nullptr != context_) {
zmq_ctx_destroy(context_);
context_ = nullptr;
}
}
public:
unsigned char init(const zmq_config &config) {
unsigned char ret = init_socket(config);
if (ret) {
return ret;
}
ret = init_link(config);
if (ret) {
return ret;
}
ret = init_sock_attribute(config);
return ret;
}
int send(const char *info, int len) {
zmq_msg_t msg = {0};
int rc = zmq_msg_init_size(&msg, len);
if (rc) {
return 0;
}
memcpy(zmq_msg_data(&msg), info, len);
rc = zmq_msg_send(&msg, socket_, 0);
zmq_msg_close(&msg);
return rc;
}
bool recv(std::string &recv_str) {
zmq_msg_t msg = {0};
int rc = zmq_msg_init(&msg);
if (rc) {
return false;
}
int len = zmq_msg_recv(&msg, socket_, 0);
bool succ = false;
if (len > 0) {
recv_str.assign((char *)zmq_msg_data(&msg), len);
succ = true;
}
zmq_msg_close(&msg);
return succ;
}
const char *get_error_msg(unsigned char code) {
auto it = sock_error_map_.find(code);
if (std::end(sock_error_map_) == it) {
return "";
}
return it->second;
}
private:
inline void init_map() {
sock_type_map_[socket_type::PULL_STYPLE] = socket_style::BIND;
sock_type_map_[socket_type::PUB_STYPLE] = socket_style::BIND;
sock_type_map_[socket_type::PUSH_STYPLE] = socket_style::CONNECT;
sock_type_map_[socket_type::SUB_STYPLE] = socket_style::CONNECT;
}
inline unsigned char init_socket(const zmq_config &config) {
if (nullptr == (context_ = zmq_ctx_new())) {
return socket_error::CONTEXT_ERROR;
}
if (nullptr == (socket_ = zmq_socket(context_, config.sock_type))) {
return socket_error::SOCKET_ERROR;
}
return socket_error::NO_ERROR;
}
unsigned char init_link(const zmq_config &config) {
auto it = sock_type_map_.find(config.sock_type);
if (std::end(sock_type_map_) == it) {
return socket_error::SOCKET_TYPE_ERROR;
}
unsigned char ret = 0;
if (socket_style::BIND == it->second) {
ret = zmq_bind(socket_, config.addr);
if (ret) {
return socket_error::BIND_ERROR;
}
return socket_error::NO_ERROR;
}
ret = zmq_connect(socket_, config.addr);
if (ret) {
return socket_error::CONNECT_ERROR;
}
return socket_error::NO_ERROR;
}
inline unsigned char init_sock_attribute(const zmq_config &config) {
unsigned char ret = zmq_setsockopt(socket_, ZMQ_SNDHWM, &config.send_hwm, sizeof(config.send_hwm));
if (ret) {
return socket_error::SOCKET_ATTRIBUTE_ERROR;
}
ret = zmq_setsockopt(socket_, ZMQ_RCVHWM, &config.recv_hwm, sizeof(config.recv_hwm));
if (ret) {
return socket_error::SOCKET_ATTRIBUTE_ERROR;
}
ret = zmq_setsockopt(socket_, ZMQ_SNDTIMEO, &config.send_timeout, sizeof(config.send_timeout));
if (ret) {
return socket_error::SOCKET_ATTRIBUTE_ERROR;
}
if (socket_type::SUB_STYPLE == config.sock_type) {
ret = zmq_setsockopt(socket_, ZMQ_SUBSCRIBE, config.topic.c_str(), config.topic.size());
if (ret) {
return socket_error::SOCKET_ATTRIBUTE_ERROR;
}
}
return socket_error::NO_ERROR;
}
private:
void *context_ = nullptr;
void *socket_ = nullptr;
private:
std::map<unsigned char, unsigned char>sock_type_map_;
std::map<unsigned char, const char *>sock_error_map_ = {
{ socket_error::NO_ERROR, "no error." },
{ socket_error::CONTEXT_ERROR, "context error." },
{ socket_error::SOCKET_ERROR, "socket error." },
{ socket_error::SOCKET_TYPE_ERROR, "socket type error." },
{ socket_error::BIND_ERROR, "bind error." },
{ socket_error::CONNECT_ERROR, "connect error." },
{ socket_error::SOCKET_ATTRIBUTE_ERROR, "socket attribute error." }
};
};
}
#endif /* SRC_ZMQ_AGENT_HPP_ */
2.zmq_server_pub.cpp
#include <iostream>
#include "zmq_agent.hpp"
int main() {
zmq_self_agent::zmq_agent server_pub;
zmq_self_agent::zmq_config server_config;
server_config.addr = "tcp://*:9999";
server_config.send_timeout = 5;
server_config.sock_type = zmq_self_agent::socket_type::PUB_STYPLE;
unsigned char ret = server_pub.init(server_config);
if (zmq_self_agent::socket_error::NO_ERROR != ret) {
std::cerr << server_pub.get_error_msg(ret) << std::endl;
return -1;
}
std::string pub_str;
while (true) {
std::cout << "publish what = ";
std::cin >> pub_str;
std::cout << "publish size = " << server_pub.send(pub_str.c_str(), pub_str.size()) << std::endl;
}
return 0;
}
3.zmq_client_sub.cpp
#include <iostream>
#include "zmq_agent.hpp"
int main(int argc, char **argv) {
zmq_self_agent::zmq_agent client_sub;
zmq_self_agent::zmq_config client_config;
if (argc != 2) {
std::cerr << "usage:./programe tcp://192.168.2.109:9999" << std::endl;
return -1;
}
client_config.addr = argv[1];
client_config.sock_type = zmq_self_agent::socket_type::SUB_STYPLE;
unsigned char ret = client_sub.init(client_config);
if (zmq_self_agent::socket_error::NO_ERROR != ret) {
std::cerr << client_sub.get_error_msg(ret) << std::endl;
return -1;
}
std::string sub_str;
while (true) {
if (true == client_sub.recv(sub_str)) {
std::cout << "client sub message = " << sub_str << std::endl;
}
}
return 0;
}
4.make.sh
g++ -g -o ZmqServerPub zmq_server_pub.cpp -std=c++11 -pthread -lpthread -lzmq
g++ -g -o ZmqClientSub zmq_client_sub.cpp -std=c++11 -pthread -lpthread -lzmq