一 需求:

将消息通信进行抽象,支持udp,tcp,zmq等方式

二 实现:

1.消息通信实体

#ifndef SRC_MESSAGE_COMMUNICATE_ENTITY_HPP_
#define SRC_MESSAGE_COMMUNICATE_ENTITY_HPP_
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <iostream>
#include <algorithm>
using namespace std;
class message_communicate_entity {
public:
message_communicate_entity() = default;
virtual ~message_communicate_entity() = default;
public:
virtual bool init() = 0;
virtual int send(const char *buf, int len) = 0;
virtual int recv(char *recv_buf, int buf_len) = 0;
};

#endif /* SRC_MESSAGE_COMMUNICATE_ENTITY_HPP_ */

2.消息通信制造者

#ifndef SRC_MESSAGE_COMMUNICATE_ENTITY_MAKER_HPP_
#define SRC_MESSAGE_COMMUNICATE_ENTITY_MAKER_HPP_
#include "message_communicate_entity.hpp"
#include <string>
#include <unordered_map>
#include <functional>
#include <memory>
class message_communicate_entity_maker {
public:
static message_communicate_entity *make(const string &entity_type) {
auto it = map_.find(entity_type);
if (end(map_) == it) {
return nullptr;
}
return it->second();
}
static unique_ptr<message_communicate_entity>make_unique_ptr(const string &entity_type) {
return unique_ptr<message_communicate_entity>(make(entity_type));
}
static std::shared_ptr<message_communicate_entity>make_shared_ptr(const string &entity_type) {
return std::shared_ptr<message_communicate_entity>(make(entity_type));
}
public:
template<class T>
struct register_t {
register_t(const string &key){
message_communicate_entity_maker::get().map_.emplace(key, [] {return new T();});
}
template<typename... Args>
register_t(const string &key, Args... args){
message_communicate_entity_maker::get().map_.emplace(key, [=] {return new T(args...);});
}
};
private:
message_communicate_entity_maker() = default;
message_communicate_entity_maker(const message_communicate_entity_maker &) = delete;
message_communicate_entity_maker operator = (const message_communicate_entity_maker &) = delete;
message_communicate_entity_maker(message_communicate_entity_maker &&) = delete;
~message_communicate_entity_maker() = default;
private:
inline static message_communicate_entity_maker &get() {
static message_communicate_entity_maker maker;
return maker;
}
private:
static unordered_map<string, function<message_communicate_entity *()>>map_; // key -- entity type such udp_unicast
};
unordered_map<string, function<message_communicate_entity *()>>message_communicate_entity_maker::map_;
#define REGISTER_MESSAGE_COMMUNICATE_ENTITY_VNAME(T) reg_entity_##T##_
#define REGISTER_MESSAGE_COMMUNICATE_ENTITY(T, key, ...) static message_communicate_entity_maker::register_t<T> REGISTER_MESSAGE_COMMUNICATE_ENTITY_VNAME(T)(key, ##__VA_ARGS__);

#endif /* SRC_MESSAGE_COMMUNICATE_ENTITY_MAKER_HPP_ */

3.udp广播服务

#ifndef SRC_UDP_BROADCAST_SERVER_HPP_
#define SRC_UDP_BROADCAST_SERVER_HPP_
#include "message_communicate_entity_maker.hpp"
class udp_broadcast_server : public message_communicate_entity {
public:
udp_broadcast_server() {
sock_fd_ = -1;
port_ = 17789;
memset(&client_addr_, 0, sizeof(client_addr_));
}
~udp_broadcast_server() {
if (sock_fd_ >= 0) {
close(sock_fd_);
}
}
public:
inline bool init() override {
return init_sock_fd() && bind_sock_fd();
}
inline bool init_sock_fd() {
sock_fd_ = socket(AF_INET, SOCK_DGRAM, 0);
if (sock_fd_ < 0) {
return false;
}
int so_broadcast = 1;
return setsockopt(sock_fd_, SOL_SOCKET, SO_BROADCAST, (char *)&so_broadcast, sizeof(so_broadcast)) >= 0;
}
inline bool bind_sock_fd() {
struct sockaddr_in addr = {0};
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = htonl(INADDR_ANY);
addr.sin_port = htons(port_);
return bind(sock_fd_, (struct sockaddr *)&addr, sizeof(addr)) >= 0;
}
inline void set_port(int port) {
port_ = port;
}
virtual int send(const char *buf, int len) override {
return sendto(sock_fd_, buf, len, 0, (struct sockaddr *)&client_addr_, sizeof(client_addr_));
}
virtual int recv(char *recv_buf, int buf_len) override {
if (buf_len <= 0 || buf_len > BUFSIZ) {
return -1;
}
char buf[BUFSIZ] = "";
socklen_t size = sizeof(struct sockaddr);
int len = recvfrom(sock_fd_, buf, sizeof(buf), 0, (struct sockaddr *)&client_addr_, &size);
if (len <= BUFSIZ && len > 0) {
len = min(len, buf_len);
memcpy(recv_buf, buf, len);
}
return len;
}
private:
int sock_fd_;
int port_;
struct sockaddr_in client_addr_;
};
REGISTER_MESSAGE_COMMUNICATE_ENTITY(udp_broadcast_server, "udp.broadcast.server");

#endif /* SRC_UDP_BROADCAST_SERVER_HPP_ */

4.udp广播客户端

#ifndef SRC_UDP_BROADCAST_CLIENT_HPP_
#define SRC_UDP_BROADCAST_CLIENT_HPP_
#include "message_communicate_entity_maker.hpp"
class udp_broadcast_client : public message_communicate_entity {
public:
udp_broadcast_client() {
sock_fd_ = -1;
port_ = 17789;
broadcast_address_ = "255.255.255.255";
memset(&client_addr_, 0, sizeof(client_addr_));
}
~udp_broadcast_client() {
if (sock_fd_ >= 0) {
close(sock_fd_);
}
}
public:
inline bool init() override {
return init_sock_fd();
}
inline bool init_sock_fd() {
sock_fd_ = socket(AF_INET, SOCK_DGRAM, 0);
if (sock_fd_ < 0) {
return false;
}
int so_broadcast = 1;
return setsockopt(sock_fd_, SOL_SOCKET, SO_BROADCAST, (char *)&so_broadcast, sizeof(so_broadcast)) >= 0;
}
inline void set_port(int port) {
port_ = port;
}
inline void set_broadcast_address(const char *address) {
broadcast_address_ = address;
}
virtual int send(const char *buf, int len) override {
struct sockaddr_in dest_addr = {0};
dest_addr.sin_family = AF_INET;
dest_addr.sin_port = htons(port_);
dest_addr.sin_addr.s_addr = inet_addr(broadcast_address_);
return sendto(sock_fd_, buf, len, 0, (struct sockaddr *)&dest_addr, sizeof(dest_addr));
}
virtual int recv(char *recv_buf, int buf_len) override {
if (buf_len <= 0 || buf_len > BUFSIZ) {
return -1;
}
char buf[BUFSIZ] = "";
socklen_t size = sizeof(struct sockaddr);
int len = recvfrom(sock_fd_, buf, sizeof(buf), 0, (struct sockaddr *)&client_addr_, &size);
if (len <= BUFSIZ && len > 0) {
len = min(len, buf_len);
memcpy(recv_buf, buf, len);
}
return len;
}
private:
int sock_fd_;
int port_;
const char *broadcast_address_;
struct sockaddr_in client_addr_;
};
REGISTER_MESSAGE_COMMUNICATE_ENTITY(udp_broadcast_client, "udp.broadcast.client");

#endif /* SRC_UDP_BROADCAST_CLIENT_HPP_ */

5.udp单播服务端

#ifndef SRC_UDP_UNICAST_SERVER_HPP_
#define SRC_UDP_UNICAST_SERVER_HPP_
#include "message_communicate_entity_maker.hpp"
class udp_unicast_server : public message_communicate_entity {
public:
udp_unicast_server() {
sock_fd_ = -1;
port_ = 27790;
memset(&client_addr_, 0, sizeof(client_addr_));
}
~udp_unicast_server() {
if (sock_fd_ >= 0) {
close(sock_fd_);
}
}
public:
inline bool init() override {
return init_sock_fd() && bind_sock_fd();
}
inline bool init_sock_fd() {
sock_fd_ = socket(AF_INET, SOCK_DGRAM, 0);
return sock_fd_ >= 0;
}
inline bool bind_sock_fd() {
struct sockaddr_in addr = {0};
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = htonl(INADDR_ANY);
addr.sin_port = htons(port_);
return bind(sock_fd_, (struct sockaddr *)&addr, sizeof(addr)) >= 0;
}
inline void set_port(int port) {
port_ = port;
}
virtual int send(const char *buf, int len) override {
return sendto(sock_fd_, buf, len, 0, (struct sockaddr *)&client_addr_, sizeof(client_addr_));
}
virtual int recv(char *recv_buf, int buf_len) override {
if (buf_len <= 0 || buf_len > BUFSIZ) {
return -1;
}
char buf[BUFSIZ] = "";
socklen_t size = sizeof(struct sockaddr);
int len = recvfrom(sock_fd_, buf, sizeof(buf), 0, (struct sockaddr *)&client_addr_, &size);
if (len <= BUFSIZ && len > 0) {
len = min(len, buf_len);
memcpy(recv_buf, buf, len);
}
return len;
}
private:
int sock_fd_;
int port_;
struct sockaddr_in client_addr_;
};
REGISTER_MESSAGE_COMMUNICATE_ENTITY(udp_unicast_server, "udp.unicast.server");

#endif /* SRC_UDP_UNICAST_SERVER_HPP_ */

6.udp单播客户端

#ifndef SRC_UDP_UNICAST_CLIENT_HPP_
#define SRC_UDP_UNICAST_CLIENT_HPP_
#include "message_communicate_entity.hpp"
class udp_unicast_client : public message_communicate_entity {
public:
udp_unicast_client() {
sock_fd_ = -1;
port_ = 27790;
unicast_address_ = "127.0.0.1";
memset(&client_addr_, 0, sizeof(client_addr_));
}
~udp_unicast_client() {
if (sock_fd_ >= 0) {
close(sock_fd_);
}
}
public:
inline bool init() override {
return init_sock_fd();
}
inline bool init_sock_fd() {
sock_fd_ = socket(AF_INET, SOCK_DGRAM, 0);
return sock_fd_ >= 0;
}
inline void set_port(int port) {
port_ = port;
}
inline void set_unicast_address(const char *address) {
unicast_address_ = address;
}
virtual int send(const char *buf, int len) override {
struct sockaddr_in dest_addr = {0};
dest_addr.sin_family = AF_INET;
dest_addr.sin_port = htons(port_);
dest_addr.sin_addr.s_addr = inet_addr(unicast_address_);
return sendto(sock_fd_, buf, len, 0, (struct sockaddr *)&dest_addr, sizeof(dest_addr));
}
virtual int recv(char *recv_buf, int buf_len) override {
if (buf_len <= 0 || buf_len > BUFSIZ) {
return -1;
}
char buf[BUFSIZ] = "";
socklen_t size = sizeof(struct sockaddr);
int len = recvfrom(sock_fd_, buf, sizeof(buf), 0, (struct sockaddr *)&client_addr_, &size);
if (len <= BUFSIZ && len > 0) {
len = min(len, buf_len);
memcpy(recv_buf, buf, len);
}
return len;
}
private:
int sock_fd_;
int port_;
const char *unicast_address_;
struct sockaddr_in client_addr_;
};
REGISTER_MESSAGE_COMMUNICATE_ENTITY(udp_unicast_client, "udp.unicast.client");

#endif /* SRC_UDP_UNICAST_CLIENT_HPP_ */

7.测试代码

void send_broadcast_thread(const char *buf) {
this_thread::sleep_for(chrono::milliseconds(100));
auto client = message_communicate_entity_maker::make_unique_ptr("udp.broadcast.client");
if (client->init() >= 0) {
reinterpret_cast<udp_broadcast_client *>(client.get())->set_broadcast_address(zeg_config::get_instance().robot_broadcast_address.c_str());
client->send(buf, strlen(buf));
}
}
void recv_broadcast_thread() {
auto server = message_communicate_entity_maker::make_unique_ptr("udp.broadcast.server");
if (server->init()) {
server->recv(udp_recv_buf, sizeof(udp_recv_buf));
}
}
TEST_CASE("testing udp broadcast entity") {
const char *buf = "hello world, I am udp broadcast test.";
thread th0(send_broadcast_thread, buf);
thread th1(recv_broadcast_thread);
th0.join();
th1.join();
CHECK(0 == strcmp(buf, udp_recv_buf));
}