对于内网服务器的通信采用zmq来进行,对于和客户端的通信采用boost的asio来。这里先来搭建zmq的基础结构。
zmq相关的知识可以去zmq官方网站查询。
这里使用zmq的push 和pull来进行通信。
先放一张结构图:
其中PushZmq是推管道, PullZmq是拉管道:
对于Push的流程是:
zmq_init()----> zmq_socket()---->zmq_connect()---->zmq_init_size()----->zmq_init_data--->zmq_send()--->zmq_msg_close()--->zmq_close()---->zma_term()
具体见代码:
PushZmq.h
- #ifndef __PUSH_ZMQ_H__
- #define __PUSH_ZMQ_H__
- #include <zmq.h>
- #include <string.h>
- #include <iostream>
- #include <glog/logging.h>
- using namespace std;
- class PushZmq
- {
- public:
- PushZmq(const char* url, void* zmqContext = NULL);
- ~PushZmq();
- size_t Send(const char* buffer, size_t length);
- private:
- string _strUrl;
- void* _ctx;
- void* _socket;
- };
- #endif
PushZmq.cpp
- #include "pushZmq.h"
- #include "proto/hello.pb.h"
- using namespace hello;
- int main()
- {
- FLAGS_minloglevel = google::INFO;
- google::InitGoogleLogging("");
- google::SetLogDestination(google::INFO, "../");
- google::SetLogFilenameExtension("log_");
- google::LogToStderr();
- string url = "tcp://127.0.0.1:5555";
- PushZmq* push = new PushZmq(url.c_str());
- //string sendContent = "Hello Pull.I am From Push!";
- PbMsgHello helloMsg;
- helloMsg.set_helloint(123456);
- helloMsg.set_hellostring("ni hao wang peng ");
- int length = helloMsg.ByteSize();
- char* buffer = (char*)malloc(length);
- helloMsg.SerializeToArray(buffer, length);
- push->Send(buffer, length);
- free(buffer);
- return 0;
- }
- PushZmq::PushZmq( const char* url, void* zmqContext /*= NULL*/ )
- :_strUrl(url)
- ,_ctx(zmqContext)
- {
- if(!_ctx)
- {
- _ctx = zmq_init(1);
- }
- _socket = zmq_socket(_ctx, ZMQ_PUSH);
- if(!_socket)
- {
- cout << "Error int zmq_socket:" << zmq_strerror(errno) << endl;
- return;
- }
- int rc = zmq_connect(_socket, _strUrl.c_str());
- if(rc != 0 )
- {
- cout << "error in zmq_connect:" << zmq_strerror(errno) << endl;
- return;
- }
- }
- PushZmq::~PushZmq()
- {
- zmq_close(_socket);
- zmq_term(_ctx);
- }
- size_t PushZmq::Send( const char* buffer, size_t length )
- {
- zmq_msg_t msg;
- int rc = zmq_msg_init_size(&msg, length);
- memcpy((char*)zmq_msg_data(&msg), buffer, length);
- rc = zmq_send(_socket, &msg, ZMQ_NOBLOCK);
- if(rc < 0)
- {
- cout << "error in zmq_send:" << zmq_strerror(errno) << endl;
- zmq_msg_close(&msg);
- return -1;
- }
- zmq_msg_close(&msg);
- LOG(INFO) << "Send Hello success: rc=" << rc;
- return rc;
- }
对于Pull的流程是:
zmq_init()--->zmq_socket()--->zmq_bind()--->zmq_poll--->zmq_msg_init()---->zmq_recv()--->zmq_msg_data()--->zmq_msg_size()-------调用具体处理函数--->zmq_close-->zmq_msg_close--->zmq_close()--->zmq_term
PullZmq.h
- #ifndef __PULL_ZMQ_H__
- #define __PULL_ZMQ_H__
- #include <zmq.h>
- #include <iostream>
- #include <string.h>
- #include <glog/logging.h>
- #include <boost/bind.hpp>
- #include <boost/function.hpp>
- using namespace std;
- class PullZmq
- {
- public:
- typedef boost::function<bool(const char*, size_t)> TypeOnMessage;
- PullZmq(const char* url, TypeOnMessage onPipeMessage, void* zmqContext=NULL);
- ~PullZmq();
- void Run();
- private:
- void* _ctx;
- string _strUrl;
- void* _socket;
- TypeOnMessage _onMessage;
- };
- #endif
PullZmq.Cpp:
- #include "PullZmq.h"
- #include "proto/hello.pb.h"
- using namespace hello;
- bool TestOnMessage( const char* buffer, size_t length );
- int main()
- {
- FLAGS_minloglevel = google::INFO;
- google::InitGoogleLogging("");
- google::SetLogDestination(google::INFO, "../");
- google::SetLogFilenameExtension("log_");
- google::LogToStderr();
- string url = "tcp://*:5555";
- PullZmq* pull = new PullZmq(url.c_str(),
- boost::bind(TestOnMessage, _1, _2));
- pull->Run();
- return 0;
- }
- PullZmq::PullZmq( const char* url, TypeOnMessage onPipeMessage, void* zmqContext )
- :_strUrl(url)
- ,_onMessage(onPipeMessage)
- , _ctx(zmqContext)
- {
- if(!_ctx)
- {
- _ctx = zmq_init(1);
- if(!_ctx)
- {
- cout << "error in zmq_init:" << zmq_strerror(errno) << endl;
- return;
- }
- }
- _socket = zmq_socket(_ctx, ZMQ_PULL);
- if (!_socket)
- {
- LOG(ERROR) << "Error in zmq_socket:" << zmq_strerror(errno);
- return;
- }
- int rc = zmq_bind(_socket, url);
- if(rc != 0)
- {
- LOG(ERROR) << "error in zmq_bind:" << zmq_strerror(errno);
- return;
- }
- }
- PullZmq::~PullZmq()
- {
- int rc = zmq_close(_socket);
- if(rc != 0)
- {
- LOG(ERROR) << "error in zmq_close:" << zmq_strerror(errno);
- }
- rc = zmq_term(_ctx);
- if(rc !=0 )
- {
- LOG(ERROR) << "error in zmq_term:" << zmq_strerror(errno);
- }
- }
- void PullZmq::Run()
- {
- zmq_pollitem_t item;
- item.socket = _socket;
- item.events = ZMQ_POLLIN;
- long pollWaitTime = 1000;
- bool bLoop = true;
- while(bLoop)
- {
- int rc = zmq_poll(&item, 1, -1);
- if(rc < 0)
- {
- LOG(ERROR) << "error in zmq_poll:" << zmq_strerror(errno);
- }else if(rc ==0)
- {
- //LOG(ERROR) << "On Idle!";
- }else
- {
- int msgCount = rc;
- while(msgCount--)
- {
- zmq_msg_t msg;
- rc = zmq_msg_init(&msg);
- if (rc !=0 )
- {
- LOG(ERROR) << "error in zmq_msg_init:" << zmq_strerror(errno);
- return;
- }
- rc = zmq_recv(_socket, &msg, 0);
- if(rc != 0)
- {
- LOG(ERROR) << "error in zmq_recv:" << zmq_strerror(errno);
- zmq_msg_close(&msg);
- continue;
- }
- void* buffer = zmq_msg_data(&msg);
- size_t len = zmq_msg_size(&msg);
- bLoop = _onMessage((const char*)buffer, len);
- zmq_msg_close(&msg);
- }
- }
- }
- }
- bool TestOnMessage( const char* buffer, size_t length )
- {
- LOG(INFO) << "TestOnMessage:";
- PbMsgHello helloMsg;
- helloMsg.ParseFromArray(buffer, length);
- LOG(INFO) << " helloInt = " << helloMsg.helloint()
- << " helloString = " << helloMsg.hellostring();
- //string content;
- //content.append(buffer);
- //LOG(INFO) << "buffer = " << content << " length = " << length;
- return true;
- }
对应Makefile为:
- all: pull push
- hello.o:
- g++ -c -o hello.o proto/hello.pb.cc
- pull: hello.o
- g++ -o pullZmq hello.o PullZmq.cpp -lzmq -lglog -lboost_filesystem -lprotobuf
- push: hello.o
- g++ -o pushZmq hello.o PushZmq.cpp -lzmq -lglog -lboost_filesystem -lprotobuf
- clean:
- rm -rf *.o
- rm -rf pullZmq
- rm -rf pushZmq
对于上文的cpp中,开启了Protobuffer的 因此需要导入protobuffer的支持,对应proto文件
hello.proto为:
- package hello;
- message PbMsgHello
- {
- required string helloString = 1;
- required int32 helloInt =2;
- }
运行以上cpp 可以实现 在push端包装一个Protobuffer的Message 在序列化之后Push到Pull端, Pull端接受到消息后进行解析 并读Message中的内容。
结果如下:
pull端:
Push端:
可见在Push端组装的 int 和string 在pull端成功解析。
下一步应该进行Message的包装,以及ProtoBuffer的反射解析。即根据类型来自动生成解析所需的Message类型。
1-6章节对于源码下载:http://download.csdn.net/detail/jcracker/6267125