websocketpp这个库是开源的,我在项目中引用,感觉还是把代码开源出来给需要的人比较好。我自己对这个库进行了简单的封装,可以做出动态库或者so库,使用起来也方便。之所有要这么封装还是因为把这个websocketpp库引入我们的项目后会报xtime命名冲突,实在没办法解决,所有重新封装了一层,彻底屏蔽websocketpp库的头文件,这样引入项目后就不会冲突了。我只提供封装后的代码,至于websocket库的编译和项目配置需要自己去做。
web_sock_server.h头文件
#pragma once
#include "pch.h"
#include <string>
#include <boost/thread.hpp>
#include <boost/function.hpp>
#if defined(_WIN32) || defined(_WIN64)
# define WEB_SOCKET_DLL_EXPORT __declspec(dllexport)
#else
# define WEB_SOCKET_DLL_EXPORT
#endif
enum WsOpcode
{
BINARY = 1,
TEXT,
OTHER
};
//定义回调函数
typedef boost::function<void(void*, const std::string, WsOpcode)> OnMessageFun;//接收消息到来的函数
typedef boost::function<void(void*)> OnOpenFun; //连接到来
typedef boost::function<void(void*, std::string)> OnCloseFun; //连接断开的函数
//单例的服务器
class WEB_SOCKET_DLL_EXPORT WebSockServer
{
private:
WebSockServer();
public:
static WebSockServer& Instance();
bool Init(uint16_t uPort, OnOpenFun openFun, OnCloseFun closeFun, OnMessageFun msgFun, void* pOiService = nullptr);
/*
如果调用StartServer,应该另开一个线程来调用,因为程序会在里面循环运行,不会返回,直到另一个线程调用StopServer函数
*/
bool StartServer();
void StopServer();
void StopListening();
/*
发送数据的接口
pClient为客户端标识
data 为要发送的数据
*/
bool Send(void* pClient, const std::string data, WsOpcode opcode = WsOpcode::BINARY);
void Close(void* pClient);
void CloseAll();
//private:
// void ThreadProccess(); //线程函数
public:
OnOpenFun m_onOpenFun;
OnCloseFun m_onCloseFun;
OnMessageFun m_onMsgFun;
private:
//boost::thread * m_threadMain; //websock 的循环线程
bool m_bServerStart; //服务是否启动的标志
};
web_sock_server.cpp源文件
#include "web_sock_server.h"
#include <websocketpp/config/asio_no_tls.hpp>
#include <websocketpp/server.hpp>
#include <map>
typedef websocketpp::server<websocketpp::config::asio> server;
using websocketpp::lib::placeholders::_1;
using websocketpp::lib::placeholders::_2;
using websocketpp::lib::bind;
typedef server::message_ptr message_ptr;
typedef std::map<void*, websocketpp::connection_hdl> ClientMap;
static server g_server;//全局的websocket服务器
//递交给上层的不能直接递交websocketpp::connection_hdl类型,因为上层没有这个类型的定义,因此用另外的类型(void*)来唯一标识一个客户端
//并且在本地维护一个客户端标识到对应实际客户端对象的映射,
static ClientMap g_mapClient;
static boost::shared_mutex rwMutext;
typedef boost::shared_lock<boost::shared_mutex> ReadLock;
typedef boost::unique_lock<boost::shared_mutex> WriteLock;
// Define a callback to handle incoming messages
static void on_message(WebSockServer* pWebserver, websocketpp::connection_hdl hdl, message_ptr msg) {
//std::cout << "on_message called with hdl: " << hdl.lock().get()
// << " and message: " << msg->get_payload()
// << std::endl;
//回调上层
if (!pWebserver->m_onMsgFun.empty())
{
WsOpcode opcode = WsOpcode::OTHER;
if (msg->get_opcode() == websocketpp::frame::opcode::value::TEXT)
{
opcode = WsOpcode::TEXT;
}
else if (msg->get_opcode() == websocketpp::frame::opcode::value::BINARY)
{
opcode = WsOpcode::BINARY;
}
pWebserver->m_onMsgFun(hdl.lock().get(), msg->get_payload(), opcode);
}
}
static void on_open(WebSockServer* pWebserver, websocketpp::connection_hdl hdl)
{
//std::cout << "client opend:" << hdl.lock().get() << std::endl;
//写锁
WriteLock writeLock(rwMutext);
//加入缓存
g_mapClient.insert(std::pair<void*, websocketpp::connection_hdl>(hdl.lock().get(), hdl));
//回调上层
if (!pWebserver->m_onOpenFun.empty())
{
pWebserver->m_onOpenFun(hdl.lock().get());
}
}
static void on_close(WebSockServer* pWebserver, websocketpp::connection_hdl hdl)
{
//std::cout << "client close:" << hdl.lock().get() << std::endl;
//回调上层
if (!pWebserver->m_onCloseFun.empty())
{
pWebserver->m_onCloseFun(hdl.lock().get(), "");
}
//写锁
WriteLock writeLock(rwMutext);
const ClientMap::iterator it = g_mapClient.find(hdl.lock().get());
//删除缓存
if (it != g_mapClient.end())
{
g_mapClient.erase(it);
return;
}
}
WebSockServer::WebSockServer()
{
m_bServerStart = false;
//m_threadMain = nullptr;
}
WebSockServer& WebSockServer::Instance()
{
static WebSockServer instance;
return instance;
}
bool WebSockServer::Send(void* pClient, const std::string data, WsOpcode opcode)
{
//读锁
ReadLock readLock(rwMutext);
//先在本地查找对应的客户端对象
const ClientMap::iterator it = g_mapClient.find(pClient);
if (it == g_mapClient.end())
{
return false;
}
websocketpp::connection_hdl hdl = it->second;
std::error_code ec;
websocketpp::frame::opcode::value sCode = websocketpp::frame::opcode::BINARY;
if (opcode == TEXT)
{
sCode = websocketpp::frame::opcode::TEXT;
}
g_server.send(hdl, data.c_str(), data.size(), sCode, ec);//发送二进制数据
//检查错误信息
if (ec.value() == 0)
{
return true;
}
else
{
return false;
}
}
void WebSockServer::Close(void* pClient)
{
//写锁
WriteLock writeLock(rwMutext);
//先在本地查找对应的客户端对象
const ClientMap::iterator it = g_mapClient.find(pClient);
if (it == g_mapClient.end())
{
//std::cout << "can not find client. " << (int)pClient << std::endl;
return;
}
websocketpp::connection_hdl hdl = it->second;
g_server.close(hdl, (websocketpp::close::status::value)0, "");
//从映射中删除
g_mapClient.erase(it);
}
void WebSockServer::CloseAll()
{
//写锁
WriteLock writeLock(rwMutext);
for (auto it = g_mapClient.begin(); it != g_mapClient.end(); it++)
{
//关闭所有连接
websocketpp::connection_hdl hdl = it->second;
g_server.close(hdl, (websocketpp::close::status::value)0, "");
}
//清空缓存
g_mapClient.clear();
}
bool WebSockServer::Init(uint16_t uPort, OnOpenFun openFun, OnCloseFun closeFun, OnMessageFun msgFun, void* pOiService)
{
m_onOpenFun = openFun;
m_onCloseFun = closeFun;
m_onMsgFun = msgFun;
try {
// Set logging settings
g_server.set_access_channels(websocketpp::log::alevel::none);
g_server.clear_access_channels(websocketpp::log::alevel::none);
// Initialize Asio
if (pOiService == nullptr)
{
g_server.init_asio();
}
else
{
g_server.init_asio((boost::asio::io_service*)pOiService);
}
// Register our message handler
g_server.set_message_handler(bind(&on_message, this, ::_1, ::_2));
g_server.set_close_handler(bind(&on_close, this, ::_1));
g_server.set_open_handler(bind(&on_open, this, ::_1));
g_server.set_reuse_addr(true);
// Listen port
g_server.listen(websocketpp::lib::asio::ip::tcp::v4(), uPort);
// Start the server accept loop
g_server.start_accept();
}
catch (websocketpp::exception const & e) {
//std::cout << e.what() << std::endl;
return false;
}
catch (...) {
//std::cout << "other exception" << std::endl;
return false;
}
return true;
}
//bool WebSockServer::StartServer()
//{
// if (!m_bServerStart)
// {
// //新开启一个线程
// m_threadMain = new boost::thread(boost::bind(&WebSockServer::ThreadProccess, this));
// if (nullptr == m_threadMain)
// {
// return false;
// }
// else
// {
// m_bServerStart = true;
// return true;
// }
// }
// else
// {
// std::cout << "server already start." << std::endl;
// return true;
// }
//}
bool WebSockServer::StartServer()
{
if (!m_bServerStart)
{
m_bServerStart = true;
g_server.run();
}
return true;
}
void WebSockServer::StopServer()
{
g_server.stop();
//等待线程结束
//m_threadMain->join();
//delete m_threadMain;
//m_threadMain = nullptr;
m_bServerStart = false;
}
void WebSockServer::StopListening()
{
g_server.stop_listening();
}
//void WebSockServer::ThreadProccess()
//{
// g_server.run();//websock服务器在此循环,直到调用g_server.stop()函数结束循环
// //while (true)
// //{
// // g_server.poll_one();
// // Sleep(100);
// //}
//}
测试代码:main.cpp
#include <iostream>
#include "web_sock_server.h"
#include <boost/bind.hpp>
void* pClient = nullptr;
void on_message(void* pClient, const std::string data, WsOpcode opcode)
{
WebSockServer::Instance().Send(pClient, data, WsOpcode::TEXT);
}
void on_open(void* pClient)
{
::pClient = pClient;
}
void on_close(void* pClient, std::string msg)
{
pClient = nullptr;
}
int main()
{
std::cout << "Hello World!\n";
WebSockServer::Instance().Init(9002,
boost::bind(on_open, _1),
boost::bind(on_close, _1, _2),
boost::bind(on_message, _1, _2, _3)
);
WebSockServer::Instance().StartServer();
std::string str;
while (std::cin >> str)
{
if (pClient != nullptr)
{
if (str == "close")
{
WebSockServer::Instance().Close(pClient);
}
else
{
WebSockServer::Instance().Send(pClient, str, WsOpcode::TEXT);
}
}
}
return 0;
}