1.定义一个协议数组
cpp
/*
struct lws_protocols {
const char *name; // 协议名称
lws_callback_function callback; // 消息/事件回调函数(核心,处理连接、消息、关闭等)
size_t per_session_data_size; // user 的大小
size_t rx_buffer_size; // 接收缓冲区大小(建议 ≥ 4096,根据业务调整)
unsigned int id; // 协议ID(内部使用,可设为 0 自动分配)
void *user; // 全局用户数据(可选,所有连接共享)
size_t tx_packet_size; // 发送数据包大小(0 表示默认)
};
*/
lws_protocols WebSocketServer::protocols[] = {
{
"ws-protocol",
WebSocketServer::static_callback,
sizeof(void*), // user 只用来存储 this 指针,所以设置为指针大小即可
1024 * 1024,
},
{ NULL, NULL, 0, 0 }
};
- 设置参数,并创建 libwebsockets 上下文
cpp
lws_context_creation_info info = {};
info.port = m_port;
info.iface = NULL; // 监听所有网络接口
info.protocols = protocols;
info.gid = -1;
info.uid = -1;
info.user = this;
// SSL 配置
if (m_use_ssl) {
info.options |= LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT;
// info.ssl_cert_filepath = "server.crt";
// info.ssl_private_key_filepath = "server.key";
}
// 创建 libwebsockets 上下文
m_context = lws_create_context(&info);
if (!m_context) {
std::cerr << "Failed to create libwebsockets context!" << std::endl;
return false;
}
- 创建一个循环,调用 lws_service 处理事件
cpp
while (m_running && m_context) {
// 处理事件,超时时间为50毫秒
lws_service(m_context, 50);
}
- 回调函数实现,由于回调函数不能是普通成员函数,所以我们需要在静态成员函数中获取 this 指针,然后调用实际的回调
cpp
int WebSocketServer::static_callback(lws* wsi, lws_callback_reasons reason,
void* user, void* in, size_t len) {
lws_context* context = lws_get_context(wsi);
WebSocketServer* server = static_cast<WebSocketServer*>(lws_context_user(context));
if (server) {
return server->instance_callback(wsi, reason, user, in, len);
}
return 0;
}
cpp
int WebSocketServer::instance_callback(lws* wsi, lws_callback_reasons reason,
void* user, void* in, size_t len) {
switch (reason) {
case LWS_CALLBACK_ESTABLISHED:
{
std::lock_guard<std::shared_mutex> lock(m_shareMutex);
std::string clientId = getUId();
m_clients[clientId] = wsi;
m_msgQueues[wsi] = std::queue<std::string>();
for (const auto& callback : m_connectedCallbacks) {
std::thread t([=]() {
callback(clientId);
});
t.detach();
}
}
break;
case LWS_CALLBACK_RECEIVE:
handleReceive(wsi, in, len);
break;
case LWS_CALLBACK_SERVER_WRITEABLE:
handleWritable(wsi);
break;
case LWS_CALLBACK_CLOSED:
{
std::lock_guard<std::shared_mutex> lock(m_shareMutex);
for (auto it = m_clients.begin(); it != m_clients.end(); ++it) {
if (it->second == wsi) {
for (const auto& callback : m_closedCallbacks) {
std::thread t([=]() {
callback(it->first);
});
t.detach();
}
m_clients.erase(it->first);
break;
}
}
m_msgQueues.erase(wsi); // 清理连接对应的发送队列
}
break;
default:
break;
}
return 0;
}
这个处理回调函数的地方我用了线程处理,因为我在接收消息回调里调用了发送消息接口,我在消息处理函数和发送消息函数里都加锁了,接收到消息时,发送消息,此时由于接收消息这里加锁了,发送消息函数得不到执行,接收消息回调就无法结束,锁也就无法释放。
- 接收消息处理
cpp
void WebSocketServer::handleReceive(lws* wsi, void* in, size_t len) {
if (lws_frame_is_binary(wsi)) {
// 处理二进制消息
} else {
// 处理文本消息
std::string message((const char*)in, len);
std::lock_guard<std::shared_mutex> lock(m_shareMutex);
for (auto it = m_clients.begin(); it != m_clients.end(); ++it) {
if (it->second == wsi) {
for (const auto& callback : m_receiveMsgCallback) {
std::thread t([=]() {
callback(it->first, message);
});
t.detach();
}
break;
}
}
}
}
- 发送消息处理
cpp
void WebSocketServer::handleWritable(lws* wsi) {
std::lock_guard<std::shared_mutex> lock(m_shareMutex);
auto it = m_msgQueues.find(wsi);
if (it == m_msgQueues.end() || it->second.empty()) {
return;
}
std::queue<std::string>& queue = it->second;
if (!queue.empty()) {
const std::string& message = queue.front();
// 准备发送缓冲区(必须预留 LWS_PRE 字节)
unsigned char buf[LWS_PRE + message.size()];
memcpy(buf + LWS_PRE, message.c_str(), message.size());
// 发送消息
int sent = lws_write(wsi, buf + LWS_PRE, message.size(), LWS_WRITE_TEXT);
if (sent < 0) {
std::cerr << "Failed to send message!" << std::endl;
} else {
//std::cout << "Message sent successfully, length: " << sent << std::endl;
}
queue.pop(); // 移除已发送的消息
if (!queue.empty()) {
lws_callback_on_writable(wsi);
}
}
}
完整代码如下
头文件
cpp
#ifndef WEBSOCKET_SERVER_H
#define WEBSOCKET_SERVER_H
#include <string>
#include <map>
#include <queue>
#include <mutex>
#include <shared_mutex>
#include <condition_variable>
#include <atomic>
#include <functional>
#include <sstream>
#include <iomanip>
#include "../thirdparty/libwebsockets/include/libwebsockets.h"
struct lws;
struct lws_context;
class WebSocketServer {
public:
explicit WebSocketServer(int port, bool use_ssl = false);
virtual ~WebSocketServer();
bool start();
void stop();
void wait();
void connectedCallback(std::function<void(const std::string&)> callback) { m_connectedCallbacks.emplace_back(callback); }
void receiveMsgCallback(std::function<void(const std::string&, const std::string&)> callback) { m_receiveMsgCallback.emplace_back(callback); }
void closedCallback(std::function<void(const std::string&)> callback) { m_closedCallbacks.emplace_back(callback); }
bool sendMessage(const std::string& client, const std::string& message);
std::string getUId() {
int counter = 0;
std::string id = std::to_string(counter);
while (m_clients.find(id) != m_clients.end()) {
++counter;
id = std::to_string(counter);
}
return id;
}
private:
static int static_callback(lws* wsi, lws_callback_reasons reason,
void* user, void* in, size_t len);
int instance_callback(lws* wsi, lws_callback_reasons reason,
void* user, void* in, size_t len);
void handleWritable(lws* wsi);
void handleReceive(lws* wsi, void* in, size_t len);
int m_port;
bool m_use_ssl;
std::atomic<bool> m_running;
lws_context* m_context;
std::map<std::string, lws*> m_clients;
std::map<lws*, std::queue<std::string>> m_msgQueues;
std::shared_mutex m_shareMutex;
std::vector<std::function<void(const std::string&)>> m_connectedCallbacks;
std::vector<std::function<void(const std::string&, const std::string&)>> m_receiveMsgCallback;
std::vector<std::function<void(const std::string&)>> m_closedCallbacks;
// 协议数组
static lws_protocols protocols[];
};
#endif // WEBSOCKET_SERVER_H
cpp 文件
cpp
#include "WebSocketServer.h"
#include <iostream>
#include <thread>
#include <signal.h>
/*
struct lws_protocols {
const char *name; // 协议名称(客户端需通过 Sec-WebSocket-Protocol 指定)
lws_callback_function callback; // 消息/事件回调函数(核心,处理连接、消息、关闭等)
size_t per_session_data_size; // user 的大小
size_t rx_buffer_size; // 接收缓冲区大小(建议 ≥ 4096,根据业务调整)
unsigned int id; // 协议ID(内部使用,可设为 0 自动分配)
void *user; // 全局用户数据(可选,所有连接共享)
size_t tx_packet_size; // 发送数据包大小(0 表示默认)
};
*/
lws_protocols WebSocketServer::protocols[] = {
{
"ws-protocol",
WebSocketServer::static_callback,
sizeof(void*), // user 只用来存储 this 指针,所以设置为指针大小即可
1024 * 1024,
},
{ NULL, NULL, 0, 0 }
};
WebSocketServer::WebSocketServer(int port, bool use_ssl)
: m_port(port), m_use_ssl(use_ssl), m_running(false), m_context(nullptr) {
}
WebSocketServer::~WebSocketServer() {
stop();
}
bool WebSocketServer::start() {
if (m_running) {
std::cerr << "Server is already running!" << std::endl;
return false;
}
// 初始化上下文创建信息
lws_context_creation_info info = {};
info.port = m_port;
info.iface = NULL; // 监听所有网络接口
info.protocols = protocols;
info.gid = -1;
info.uid = -1;
info.user = this;
// SSL 配置
if (m_use_ssl) {
info.options |= LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT;
// info.ssl_cert_filepath = "server.crt";
// info.ssl_private_key_filepath = "server.key";
}
// 创建 libwebsockets 上下文
m_context = lws_create_context(&info);
if (!m_context) {
std::cerr << "Failed to create libwebsockets context!" << std::endl;
return false;
}
m_running = true;
std::cout << "WebSocket server started on port " << m_port << std::endl;
// 这里会阻塞主线程,也可以开一个线程处理
while (m_running && m_context) {
// 处理事件,超时时间为50毫秒
lws_service(m_context, 50);
}
return true;
}
void WebSocketServer::stop() {
if (m_running) {
m_running = false;
if (m_context) {
std::this_thread::sleep_for(std::chrono::milliseconds(100));
lws_context_destroy(m_context);
m_context = nullptr;
}
std::cout << "WebSocket server stopped." << std::endl;
}
}
int WebSocketServer::static_callback(lws* wsi, lws_callback_reasons reason,
void* user, void* in, size_t len) {
lws_context* context = lws_get_context(wsi);
WebSocketServer* server = static_cast<WebSocketServer*>(lws_context_user(context));
if (server) {
return server->instance_callback(wsi, reason, user, in, len);
}
return 0;
}
int WebSocketServer::instance_callback(lws* wsi, lws_callback_reasons reason,
void* user, void* in, size_t len) {
switch (reason) {
case LWS_CALLBACK_ESTABLISHED:
{
std::lock_guard<std::shared_mutex> lock(m_shareMutex);
std::string clientId = getUId();
m_clients[clientId] = wsi;
m_msgQueues[wsi] = std::queue<std::string>();
for (const auto& callback : m_connectedCallbacks) {
std::thread t([=]() {
callback(clientId);
});
t.detach();
}
}
break;
case LWS_CALLBACK_RECEIVE:
handleReceive(wsi, in, len);
break;
case LWS_CALLBACK_SERVER_WRITEABLE:
handleWritable(wsi);
break;
case LWS_CALLBACK_CLOSED:
{
std::lock_guard<std::shared_mutex> lock(m_shareMutex);
for (auto it = m_clients.begin(); it != m_clients.end(); ++it) {
if (it->second == wsi) {
for (const auto& callback : m_closedCallbacks) {
std::thread t([=]() {
callback(it->first);
});
t.detach();
}
m_clients.erase(it->first);
break;
}
}
m_msgQueues.erase(wsi); // 清理连接对应的发送队列
}
break;
default:
break;
}
return 0;
}
void WebSocketServer::handleWritable(lws* wsi) {
std::lock_guard<std::shared_mutex> lock(m_shareMutex);
auto it = m_msgQueues.find(wsi);
if (it == m_msgQueues.end() || it->second.empty()) {
return;
}
std::queue<std::string>& queue = it->second;
if (!queue.empty()) {
const std::string& message = queue.front();
// 准备发送缓冲区(必须预留 LWS_PRE 字节)
unsigned char buf[LWS_PRE + message.size()];
memcpy(buf + LWS_PRE, message.c_str(), message.size());
// 发送消息
int sent = lws_write(wsi, buf + LWS_PRE, message.size(), LWS_WRITE_TEXT);
if (sent < 0) {
std::cerr << "Failed to send message!" << std::endl;
} else {
//std::cout << "Message sent successfully, length: " << sent << std::endl;
}
queue.pop(); // 移除已发送的消息
if (!queue.empty()) {
lws_callback_on_writable(wsi);
}
}
}
void WebSocketServer::handleReceive(lws* wsi, void* in, size_t len) {
if (lws_frame_is_binary(wsi)) {
// 处理二进制消息
} else {
// 处理文本消息
std::string message((const char*)in, len);
std::lock_guard<std::shared_mutex> lock(m_shareMutex);
for (auto it = m_clients.begin(); it != m_clients.end(); ++it) {
if (it->second == wsi) {
for (const auto& callback : m_receiveMsgCallback) {
std::thread t([=]() {
callback(it->first, message);
});
t.detach();
}
break;
}
}
}
}
void WebSocketServer::wait() {
while (m_running) {
std::this_thread::sleep_for(std::chrono::milliseconds(100));
}
}
bool WebSocketServer::sendMessage(const std::string& client, const std::string& message) {
if (!m_running) {
return false;
}
{
std::lock_guard<std::shared_mutex> lock(m_shareMutex);
auto it = m_clients.find(client);
if (it == m_clients.end()) {
return false;
}
lws *wsi = it->second;
auto itsend = m_msgQueues.find(wsi);
if (itsend != m_msgQueues.end()) {
itsend->second.push(message);
} else {
return false;
}
// 触发发送消息事件
lws_callback_on_writable(wsi);
}
return true;
}
main 函数
cpp
#include "WebSocketServer.h"
int main(int argc, char **argv)
{
WebSocketServer server(1236);
server.connectedCallback([](const std::string& id) {
std::cout << "[连接] 客户端: " << id << std::endl;
});
server.receiveMsgCallback([&](const std::string& id, const std::string& msg) {
server.sendMessage(id, msg);
});
server.closedCallback([](const std::string& id) {
std::cout << "[断开] 客户端: " << id << std::endl;
});
server.start();
return 0;
}