/*************************************************************************
* > File Name: ZMQ_PipeSocket.h
* > Author: wangzhicheng
* > Mail: 2363702560@qq.com
* > Created Time: 2017-02-07
* > statement: ZMQ封装类
*************************************************************************/
#ifndef ZMQ_PIPE_SOCKET_H
#define ZMQ_PIPE_SOCKET_H
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <assert.h>
#include <string.h>
#include <stdint.h>
#include <zmq.h>
#include <string>
#include <set>
namespace zmqpipe
{
using namespace std;
class ZMQ_PIPESocket
{
private:
void *m_pContext;
void *m_pSocket;
int m_nSocketType;
string m_strSendServer; // 发送的服务器地址
public:
ZMQ_PIPESocket();
~ZMQ_PIPESocket();
/*
* @brief 初始化zmq
* */
bool Init(int SocketType, const string &addr, int sendhwm = 1000, int recvhwm = 1000, int sendtimeout = 1000);
/*
* @brief 发送info指向的对象
* @len 对象的大小 字节数
* @return 发送成功返回true
* */
bool Send(void *info, int len);
/*
* @brief 发送string对象
* @return 发送成功返回true
* */
bool Send(const string &strSend);
/*
* @brief 接收数据 接收的数据由info指向
* @return 接收成功返回true
* */
bool Recv(void *info);
/*
* @brief 接收string对象数据
* @return 接收成功返回true
* */
bool Recv(string &strRecv);
/*
* @brief 获取发送服务器地址
* */
inline void GetSendAddr(string &strOut)
{
strOut = m_strSendServer;
}
/*
* @brief recieving from a socket is over
* */
bool RecvOver();
};
}
#endif
/*************************************************************************
* > File Name: ZMQ_PipeSocket.cpp
* > Author: wangzhicheng
* > Mail: 2363702560@qq.com
* > Created Time: 2017-02-07
* > statement: ZMQ封装类
*************************************************************************/
#include "ZMQ_PipeSocket.h"
namespace zmqpipe
{
ZMQ_PIPESocket::ZMQ_PIPESocket()
{
m_pContext = NULL;
m_pSocket = NULL;
}
bool ZMQ_PIPESocket::Init(int SocketType,
const string &addr,
int sendhwm,
int recvhwm,
int sendtimeout)
{
m_pContext = zmq_ctx_new();
if(!m_pContext) return false;
m_pSocket = zmq_socket(m_pContext, SocketType);
if(!m_pSocket) return false;
int rc;
switch(SocketType)
{
// case ZMQ_REP:
case ZMQ_PULL:
case ZMQ_PUB:
rc = zmq_bind(this->m_pSocket, addr.c_str());
break;
case ZMQ_REP:
case ZMQ_REQ:
case ZMQ_PUSH:
case ZMQ_SUB:
rc = zmq_connect(this->m_pSocket, addr.c_str());
break;
default:
return false;
}
rc = zmq_setsockopt(m_pSocket, ZMQ_SNDHWM, &sendhwm, sizeof(sendhwm));
if(rc) return false;
rc = zmq_setsockopt(m_pSocket, ZMQ_RCVHWM, &recvhwm, sizeof(recvhwm));
if(rc) return false;
rc = zmq_setsockopt(m_pSocket, ZMQ_SNDTIMEO, &sendtimeout, sizeof(sendtimeout));
if(rc) return false;
m_strSendServer = addr;
return true;
}
/*
* @brief 发送info指向的对象
* @len 对象的大小 字节数
* */
bool ZMQ_PIPESocket::Send(void *info, int len)
{
int rc;
zmq_msg_t msg;
rc = zmq_msg_init_size(&msg, len);
if(rc) return false;
memcpy(zmq_msg_data(&msg), (char *)info, len);
rc = zmq_msg_send(&msg, this->m_pSocket, 0);
return rc == len;
}
/*
* @brief 发送string对象
* */
bool ZMQ_PIPESocket::Send(const string &strSend)
{
int rc;
size_t len = strSend.size();
zmq_msg_t msg;
rc = zmq_msg_init_size(&msg, len);
if(rc) return false;
memcpy(zmq_msg_data(&msg), strSend.c_str(), len);
size_t Len = zmq_msg_send(&msg, this->m_pSocket, 0);
return Len == len;
}
/*
* @brief 接收数据 接收的数据由info指向
* */
bool ZMQ_PIPESocket::Recv(void *info)
{
int rc;
zmq_msg_t msg;
rc = zmq_msg_init(&msg);
if(rc) return false;
int len = zmq_msg_recv(&msg, this->m_pSocket, 0); // 阻塞方式
if(len <= 0) return false;
memcpy(info, (char *)zmq_msg_data(&msg), len);
if(zmq_msg_close(&msg)) return false;
return true;
}
/*
* @brief 接收string对象数据
* */
bool ZMQ_PIPESocket::Recv(string &strRecv)
{
int rc;
zmq_msg_t msg;
rc = zmq_msg_init(&msg);
if(rc) return false;
int len = zmq_msg_recv(&msg, this->m_pSocket, 0); // 阻塞方式
if(len <= 0) return false;
strRecv.assign((char *)zmq_msg_data(&msg), len);
if(zmq_msg_close(&msg)) return false;
return true;
}
/*
* @brief recieving from a socket is over
* */
bool ZMQ_PIPESocket::RecvOver()
{
int64_t more;
size_t more_size = sizeof(more);
zmq_getsockopt(m_pSocket, ZMQ_RCVMORE, &more, &more_size);
return more <= 0;
}
ZMQ_PIPESocket::~ZMQ_PIPESocket()
{
if(m_pSocket)
{
zmq_close(m_pSocket);
m_pSocket = NULL;
}
if(m_pContext)
{
zmq_ctx_destroy(m_pContext);
m_pContext = NULL;
}
}
}
/*************************************************************************
* > File Name: ZMQ_Poll.h
* > Author: wangzhicheng
* > Mail: 2363702560@qq.com
* > Created Time: 2017-02-07
* > statement: zmq poll for selecting zmq socket
*************************************************************************/
#ifndef ZMQ_POLL_H
#define ZMQ_POLL_H
#include <stdio.h>
#include <zmq.h>
#include <vector>
namespace zmqpoll
{
static const int MAXPOLLNUM = 1024;
using namespace std;
class ZMQ_Poll
{
private:
vector<zmq_pollitem_t>m_vecPollItems;
vector<bool>m_vecExisted;
int m_nMaxIndex;
public:
/*
* @brief constructor:initialize m_vecPollItems
* */
ZMQ_Poll()
{
m_vecPollItems.resize(MAXPOLLNUM);
m_vecExisted.resize(MAXPOLLNUM);
m_nMaxIndex = -1;
}
/*
* @brief add a zmq socket into the poll
* @psocket socket ptr
* @id the identifier for the zmq object
* @events the poll events
* @return true if adding is ok
* */
bool AddPoll(void *psocket, int id, short events);
/*
* @brief the poll events happen
* @return true if happen
* */
inline bool IsPollComing(int id, short events)
{
return m_vecPollItems[id].revents & events;
}
/*
* @brief to poll the events
* @return >= 0 is ok -1 error
* */
inline int Poll(long timeout)
{
return zmq_poll(&m_vecPollItems[0], m_nMaxIndex + 1, timeout);
}
};
}
#endif
/*************************************************************************
* > File Name: ZMQ_Poll.cpp
* > Author: wangzhicheng
* > Mail: 2363702560@qq.com
* > Created Time: 2017-02-07
* > statement: zmq poll for selecting zmq socket
*************************************************************************/
#include "ZMQ_Poll.h"
namespace zmqpoll
{
/*
* @brief add a zmq socket into the poll
* @zmq_pipesocket zmq object
* @id the identifier for the zmq object
* @events the poll events
* @return true if adding is ok
* */
bool ZMQ_Poll::AddPoll(void *psocket, int id, short events)
{
// validate the entry and the existence
if(id < 0 && id >= MAXPOLLNUM) return false;
if(m_vecExisted[id]) return false;
if(id > m_nMaxIndex) m_nMaxIndex = id;
// add into the poll
zmq_pollitem_t pollitem = {0};
pollitem.socket = psocket;
pollitem.events = events;
m_vecPollItems[id] = pollitem;
m_vecExisted[id] = true;
return true;
}
}
/*************************************************************************
* > File Name: ZMQ_Agent.h
* > Author: wangzhicheng
* > Mail: 2363702560@qq.com
* > Created Time: 2017-02-07
* > statement: zmq agent
*************************************************************************/
#ifndef ZMQ_AGENT_H
#define ZMQ_AGENT_H
#include <stdint.h>
#include <string>
#include "ZMQ_Poll.h"
namespace zmqagent
{
using namespace zmqpoll;
enum AGENTID
{
FRONT,
BACK
};
class ZMQ_Agent
{
private:
void *m_pContext;
void *m_pfrontend;
void *m_pbackend;
ZMQ_Poll m_ZmqAgent;
public:
/*
* @brief constructor:
* */
ZMQ_Agent()
{
m_pContext = nullptr;
m_pfrontend = nullptr;
m_pbackend = nullptr;
}
/*
* @brief destructor:
* */
~ZMQ_Agent()
{
if(m_pfrontend) zmq_close(m_pfrontend);
if(m_pbackend) zmq_close(m_pbackend);
if(m_pContext) zmq_ctx_destroy(m_pContext);
}
/*
* @brief constructor:initialize context and socket
* @return true if init is ok
* */
bool Init(int frontend_port, int backend_port);
/*
* @brief whether front end can receive data
* @return true if yes
* */
int Poll();
/*
* @brief whether front end can receive data
* @return true if yes
* */
bool IsFrontReadyRecv();
/*
* @brief whether back end can receive data
* @return true if yes
* */
bool IsBackReadyRecv();
/*
* @brief receive data from clients and send to the back end
* @return true is recv is over
* */
bool FrontDeal();
/*
* @brief receive data from the front and send to the front end
* @return true is recv is over
* */
bool BackDeal();
};
}
#endif
/*************************************************************************
* > File Name: ZMQ_Agent.cpp
* > Author: wangzhicheng
* > Mail: 2363702560@qq.com
* > Created Time: 2017-02-07
* > statement: zmq agent
*************************************************************************/
#include "ZMQ_Agent.h"
namespace zmqagent
{
/*
* @brief constructor:initialize context and socket
* @return true if init is ok
* */
bool ZMQ_Agent::Init(int frontend_port, int backend_port)
{
// new context and socket
m_pContext = zmq_ctx_new();
if(!m_pContext) return false;
m_pfrontend = zmq_socket(m_pContext, ZMQ_ROUTER);
m_pbackend = zmq_socket(m_pContext, ZMQ_DEALER);
if(!m_pfrontend || !m_pbackend) return false;
// bind
char buf[64];
const static string comm = "tcp://*:";
string addr;
if(frontend_port < 0 || frontend_port >= 65535) return false;
if(backend_port < 0 || backend_port >= 65535) return false;
snprintf(buf, sizeof buf, "%d", frontend_port);
addr = comm;
addr += buf;
if(zmq_bind(m_pfrontend, addr.c_str())) return false;
snprintf(buf, sizeof buf, "%d", backend_port);
addr = comm;
addr += buf;
if(zmq_bind(m_pbackend, addr.c_str())) return false;
// add into poll
m_ZmqAgent.AddPoll(m_pfrontend, FRONT, ZMQ_POLLIN);
m_ZmqAgent.AddPoll(m_pbackend, BACK, ZMQ_POLLIN);
return true;
}
/*
* @brief whether front end can receive data
* @return true if yes
* */
int ZMQ_Agent::Poll()
{
return m_ZmqAgent.Poll(-1);
}
/*
* @brief whether front end can receive data
* @return true if yes
* */
bool ZMQ_Agent::IsFrontReadyRecv()
{
return m_ZmqAgent.IsPollComing(FRONT, ZMQ_POLLIN);
}
/*
* @brief whether back end can receive data
* @return true if yes
* */
bool ZMQ_Agent::IsBackReadyRecv()
{
return m_ZmqAgent.IsPollComing(BACK, ZMQ_POLLIN);
}
/*
* @brief receive data from clients and send to the back end
* @return true is recv is over
* */
bool ZMQ_Agent::FrontDeal()
{
int64_t more;
size_t more_size = sizeof(more);
zmq_msg_t message;
zmq_msg_init(&message);
zmq_msg_recv(&message, m_pfrontend, 0);
zmq_getsockopt(m_pfrontend, ZMQ_RCVMORE, &more, &more_size);
zmq_msg_send(&message, m_pbackend, more ? ZMQ_SNDMORE : 0);
zmq_msg_close(&message);
if(!more) return true;
else return false;
}
/*
* @brief receive data from the front and send to the front end
* @return true is recv is over
* */
bool ZMQ_Agent::BackDeal()
{
int64_t more;
size_t more_size = sizeof(more);
zmq_msg_t message;
zmq_msg_init(&message);
zmq_msg_recv(&message, m_pbackend, 0);
zmq_getsockopt(m_pbackend, ZMQ_RCVMORE, &more, &more_size);
zmq_msg_send(&message, m_pfrontend, more ? ZMQ_SNDMORE : 0);
zmq_msg_close(&message);
if(!more) return true;
else return false;
}
}
/*************************************************************************
> File Name: test.cpp
> Author: wangzhicheng
> Mail: 2363702560@qq.com
> Created Time:2017-02-07
************************************************************************/
#include <iostream>
#include <vector>
#include <thread>
#include <chrono>
#include "ZMQ_PipeSocket.h"
//#include "ZMQ_Poll.h"
#include "ZMQ_Agent.h"
using namespace zmqpipe;
using namespace zmqagent;
static const string ADDR0 = "tcp://127.0.0.1:8888";
static const string ADDR1 = "tcp://127.0.0.1:9999";
static const string ADDR2 = "tcp://*:8888";
static const string ADDR3 = "tcp://*:9999";
static const chrono::milliseconds dura(1000); // 1s
void client_thread()
{
string str;
ZMQ_PIPESocket sender;
if(!sender.Init(ZMQ_REQ, ADDR0, false))
{
cerr << "client init failed...!" << endl;
exit(EXIT_FAILURE);
}
while(1)
{
if(!sender.Send("Hello World...!"))
{
cerr << "client send failed...!" << endl;
}
if(!sender.Recv(str))
{
cerr << "client recv failed...!" << endl;
}
else cout << "client recv = " << str << endl;
this_thread::sleep_for(dura);
}
}
void server_thread()
{
string str;
ZMQ_PIPESocket receiver;
if(!receiver.Init(ZMQ_REP, ADDR1, false))
{
cerr << "server init failed...!" << endl;
exit(EXIT_FAILURE);
}
while(1)
{
if(!receiver.Recv(str))
{
cerr << "server recv failed...!" << endl;
}
else cout << "server recv = " << str << endl;
this_thread::sleep_for(dura);
if(!receiver.Send("Hello World...!"))
{
cerr << "server send failed...!" << endl;
}
}
}
void agent_thread()
{
ZMQ_Agent agent;
if(!agent.Init(8888, 9999))
{
cerr << "agent init failed...!" << endl;
exit(EXIT_FAILURE);
}
while(1)
{
int rc = agent.Poll();
if(rc < 0)
{
cerr << "zmq poll error...!" << endl;
break;
}
else
if(!rc)
{
cout << "no poll event happens...!" << endl;
continue;
}
if(agent.IsFrontReadyRecv())
{
while(1)
{
if(agent.FrontDeal()) break;
}
}
if(agent.IsBackReadyRecv())
{
while(1)
{
if(agent.BackDeal()) break;
}
}
}
}
int main()
{
thread th_client(client_thread);
thread th_server(server_thread);
thread th_agent(agent_thread);
th_client.join();
th_server.join();
th_agent.join();
return 0;
}
CC=g++
all:
$(CC) -std=c++11 -g -o TestAgent test.cpp ZMQ_PipeSocket.h ZMQ_PipeSocket.cpp ZMQ_Poll.h ZMQ_Poll.cpp ZMQ_Agent.h ZMQ_Agent.cpp -lzmq -pthread
export LD_LIBRARY_PATH=/usr/local/lib:$LD_LIBRARY_PATH