使用websocketpp,需要安装boost。
解压 boost_1_73_0.tar.gz
tar -zvfx boost_1_73_0.tar.gz
运行bootstrap.sh后,生成b2,直接运行b2;如果需要移植到ARM平台,则需要在project-config.jam文件将using gcc修改如下:
using gcc : : arm-linux-gnueabihf-gcc;
生成的库文件在stage目录中。
下面是websocket服务器例程,该服务器功能用于推送数据到客户端,对连接到服务器的客户端,服务器定时推送数据到客户端。这里简单实现了两个推送地址,分别为ws://localhost:9000/push/helloworld和ws://localhost:9000/current/status。
#include <websocketpp/config/asio_no_tls.hpp>
#include <websocketpp/server.hpp>
#include <set>
#include <string>
#include <iostream>
/*
#include <boost/thread.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/thread/condition_variable.hpp>*/
#include <websocketpp/common/thread.hpp>
typedef websocketpp::server<websocketpp::config::asio> server;
using websocketpp::connection_hdl;
using websocketpp::lib::placeholders::_1;
using websocketpp::lib::placeholders::_2;
using websocketpp::lib::bind;
using websocketpp::lib::thread;
using websocketpp::lib::mutex;
using websocketpp::lib::lock_guard;
using websocketpp::lib::unique_lock;
using websocketpp::lib::condition_variable;
enum action_type {
SUBSCRIBE,
UNSUBSCRIBE,
MESSAGE
};
typedef server::message_ptr message_ptr;
struct action {
action(action_type t, std::string s, connection_hdl h) : type(t), struri(s), hdl(h) {}
action(action_type t, std::string s, connection_hdl h, server::message_ptr m)
: type(t), struri(s), hdl(h), msg(m) {}
action_type type;
std::string struri;
websocketpp::connection_hdl hdl;
server::message_ptr msg;
};
/**************************************************************************************************/
class broadcast_server {
public:
broadcast_server() {
// Initialize Asio Transport
m_server.init_asio();
// 连接打开回调函数
m_server.set_open_handler(bind(&broadcast_server::on_open,this,::_1));
//连接关闭回调函数
m_server.set_close_handler(bind(&broadcast_server::on_close,this,::_1));
//接收websocket数据回调函数
m_server.set_message_handler(bind(&broadcast_server::on_message,this,::_1,::_2));
}
void run(uint16_t port) {
m_server.listen(port);
m_server.start_accept();
set_helloworld_timer();
set_status_timer();
try {
m_server.run();
} catch (const std::exception & e) {
std::cout << e.what() << std::endl;
}
}
void set_status_timer() {
m_sensor_timer = m_server.set_timer(
10000,
websocketpp::lib::bind(
&broadcast_server::robot_status,
this,
websocketpp::lib::placeholders::_1
)
);
}
void robot_status(websocketpp::lib::error_code const & ec) {
if (ec) {
m_server.get_alog().write(websocketpp::log::alevel::app, "Timer Error: "+ec.message());
return;
}
std::stringstream val;
std::string data = struct_robot_status();
val << "current status \r\n";
con_list::iterator it;
for (it = m_status_connections.begin(); it != m_status_connections.end(); ++it) {
m_server.send(*it,val.str(),websocketpp::frame::opcode::text);
}
set_status_timer();
}
/************************************************************************/
void set_helloworld_timer() {
m_helloworld_timer= m_server.set_timer(
2000,
websocketpp::lib::bind(
&broadcast_server::sensor_value,
this,
websocketpp::lib::placeholders::_1
)
);
}
void helloworld_routine(websocketpp::lib::error_code const & ec) {
if (ec) {
m_server.get_alog().write(websocketpp::log::alevel::app, "Timer Error: "+ec.message());
return ;
}
std::stringstream val;
std::string data = struct_sensor_data();
val << "hello world \r\n";
con_list::iterator it;
for (it = m_sensor_connections.begin(); it != m_sensor_connections.end(); ++it) {
m_server.send(*it, val.str(), websocketpp::frame::opcode::text);
}
set_helloworld_timer();
}
/************************************************************************/
void on_open(connection_hdl hdl) {
{
lock_guard<mutex> guard(m_action_lock);
server::connection_ptr con = m_server.get_con_from_hdl(hdl);
websocketpp::http::parser::request rt = con->get_request();
m_actions.push(action(SUBSCRIBE, rt.get_uri(), hdl));
}
m_action_cond.notify_one();
}
void on_close(connection_hdl hdl) {
{
lock_guard<mutex> guard(m_action_lock);
server::connection_ptr con = m_server.get_con_from_hdl(hdl);
websocketpp::http::parser::request rt = con->get_request();
m_actions.push(action(UNSUBSCRIBE, rt.get_uri(), hdl));
}
m_action_cond.notify_one();
}
void on_message(connection_hdl hdl, server::message_ptr msg) {
{
lock_guard<mutex> guard(m_action_lock);
server::connection_ptr con = m_server.get_con_from_hdl(hdl);
websocketpp::http::parser::request rt = con->get_request();
m_actions.push(action(MESSAGE, rt.get_uri(), hdl, msg));
}
m_action_cond.notify_one();
}
void process_messages() {
while(1) {
unique_lock<mutex> lock(m_action_lock);
while(m_actions.empty()) {
m_action_cond.wait(lock);
}
action a = m_actions.front();
m_actions.pop();
lock.unlock();
if(0 == a.struri.compare(std::string("/push/helloworld"))) {
if (a.type == SUBSCRIBE) {
lock_guard<mutex> guard(m_connection_lock);
m_helloworld_connections.insert(a.hdl);
} else if (a.type == UNSUBSCRIBE) {
lock_guard<mutex> guard(m_connection_lock);
m_helloworld_connections.erase(a.hdl);
} else if (a.type == MESSAGE) {
lock_guard<mutex> guard(m_connection_lock);
} else {
// undefined.
}
} else if(0 == a.struri.compare(std::string("/current/status"))) {
if (a.type == SUBSCRIBE) {
lock_guard<mutex> guard(m_connection_lock);
m_status_connections.insert(a.hdl);
} else if (a.type == UNSUBSCRIBE) {
lock_guard<mutex> guard(m_connection_lock);
m_status_connections.erase(a.hdl);
} else if (a.type == MESSAGE) {
lock_guard<mutex> guard(m_connection_lock);
} else {
// undefined.
}
} else {
}
}
}
private:
typedef std::set<connection_hdl,std::owner_less<connection_hdl> > con_list;
server m_server;
server::timer_ptr m_helloworld_timer;
server::timer_ptr m_status_timer;
con_list m_helloworld_connections;
con_list m_status_connections;
std::queue<action> m_actions;
mutex m_action_lock;
mutex m_connection_lock;
condition_variable m_action_cond;
};
int main(int argc, char *argv[])
{
try {
broadcast_server server_instance;
thread t(bind(&broadcast_server::process_messages,&server_instance));
server_instance.run(9000);
t.join();
} catch (websocketpp::exception const & e) {
std::cout << e.what() << std::endl;
}
return 0;
}
编译命令:
g++ -std=gnu++14 -o server websocket_server.cpp -I/DIR/websocketpp -I/DIR/boost/include -L/DIR/boost/lib -lboost_system -lboost_chrono -lpthread