websocketpp/websocket++库教程/服务端代码封装

本文介绍了一个基于WebSocketPP库的封装方案,解决了项目中命名冲突的问题,并提供了动态库或so库的构建方式。通过封装,实现了单例服务器模式,定义了回调函数用于消息处理、连接建立和断开,同时提供了发送数据和关闭连接的接口。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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;
}

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值