文章详情
linux中使用websocketpp完成浏览器与服务器通讯
Posted on 2024-06-06 07:32:34 by 主打一个C++
//项目测试代码.h
#pragma once
#include <set>
#include <websocketpp/config/asio_no_tls.hpp>
#include <websocketpp/server.hpp>
#include <string>
#include <iconv.h>
#include <cstring>
#include <cerrno>
#include <iostream>
#include <unordered_map>
#include <mutex>
#include <list>
#include <dirent.h>
#include <vector>
#include "./include/Log.h"
//#include "./include/CSqlite3.h"
//#include "./include/CJson.h"
typedef websocketpp::server<websocketpp::config::asio> server;
using websocketpp::connection_hdl;
using websocketpp::log::alevel;
using websocketpp::lib::placeholders::_1;
using websocketpp::lib::placeholders::_2;
using websocketpp::lib::bind;
class broadcast_server;
class broadcast_server {
private:
size_t NewMenoryAlign(size_t _size, size_t _align = 256) {
return _size + (_align - (_size % _align));
}
bool ConvertText_used(const char* _in, std::string& _out, const char* _fromCode = "GBK\0", const char* _tocode = "UTF-8\0") {
//DbgPrint("ConvertText=[%s]\n", _in);
iconv_t cd = iconv_open(_tocode, _fromCode);
if (cd == (iconv_t)(-1)) {
DbgPrint("iconv_open failed!\n");
return false;
}
size_t inBytesLeft = strlen(_in);
size_t outBytesLeft = NewMenoryAlign(inBytesLeft * 4 + 4);
char* outputBuffer = new char[outBytesLeft];
if (outputBuffer == NULL) {
iconv_close(cd);
DbgPrint("Memory allocation failed!\n");
return false;
}
char* outPtr = outputBuffer;
memset(outPtr, 0, outBytesLeft);
if (iconv(cd, (char**)&_in, &inBytesLeft, &outPtr, &outBytesLeft) == (size_t)(-1)) {
DbgPrint("%s %s\n", _in, outputBuffer);
delete[] outputBuffer;
iconv_close(cd);
DbgPrint("iconv failed!\n");
return false;
}
iconv_close(cd);
_out = outputBuffer;
delete[] outputBuffer;
return true;
}
// 自定义实现 encodeURIComponent
std::string encodeURIComponent(const std::string& value) {
std::ostringstream encoded;
for (unsigned char c : value) {
if (isalnum(c) || c == '-' || c == '_' || c == '.' || c == '~') {
encoded << c; // 直接添加
}
else {
encoded << '%' << std::uppercase << std::hex << static_cast<int>(c); // 编码
}
}
return encoded.str();
}
// 自定义实现 decodeURIComponent
std::string decodeURIComponent(const std::string& value) {
std::string decoded;
for (size_t i = 0; i < value.length(); ++i) {
if (value[i] == '%') {
if (i + 2 < value.length()) {
std::string hex = value.substr(i + 1, 2);
char c = static_cast<char>(std::stoi(hex, nullptr, 16));
decoded += c; // 解码
i += 2; // 跳过已处理的两个字符
}
}
else if (value[i] == '+') {
decoded += ' '; // 将加号替换为空格
}
else {
decoded += value[i]; // 直接添加
}
}
return decoded;
}
public:
broadcast_server() {
m_server.init_asio();
//绑定回调
m_server.set_open_handler(bind(&broadcast_server::on_open, this, std::placeholders::_1));
m_server.set_close_handler(bind(&broadcast_server::on_close, this, std::placeholders::_1));
m_server.set_message_handler(bind(&broadcast_server::on_message, this, std::placeholders::_1, std::placeholders::_2));
// 清除所有的日志
m_server.clear_access_channels(alevel::all);
m_server.clear_error_channels(alevel::all);
}
void run(uint16_t port) {
m_server.reset();
m_server.set_reuse_addr(true);
m_server.listen(port);
m_server.start_accept();
m_server.run();
}
private:
virtual void on_open(connection_hdl hdl) {
printf("on_open\n");
}
virtual void on_close(connection_hdl hdl) {
printf("on_close\n");
}
virtual void on_message(connection_hdl hdl, server::message_ptr msg) {
std::string message = msg->get_payload();
this->handleMsg(hdl, message);
}
private:
int GetTcpSocket(const connection_hdl& _hdl);
void PackSendMsg(const connection_hdl& _hdl, const std::string& _msg, bool convertText = false);
void SendMsg(const connection_hdl& _hdl, const std::string& _msg);
void handleMsg(const connection_hdl& _hdl, const std::string& _msg);
bool getFiles(const std::string& directory, const std::string& _extension, std::vector<std::string>& _list);
private:
server m_server;
//std::unordered_map<long long, PS_USER_INFO> m_userList;std::mutex m_userList_lock;
};
//测试代码.cpp
int broadcast_server::GetTcpSocket(const connection_hdl& _hdl)
{
return (int)m_server.get_con_from_hdl(_hdl)->get_socket().native();
}
void broadcast_server::PackSendMsg(const connection_hdl& _hdl, const std::string& _msg, bool convertText) {
std::string message;
if (convertText) {
if (!ConvertText_used(_msg.c_str(), message)) {
DbgPrint("ConvertText_used error\n");
return;
}
}
else {
message = _msg;
}
m_server.send(_hdl, encodeURIComponent(message), websocketpp::frame::opcode::text);
}
void broadcast_server::SendMsg(const connection_hdl& _hdl, const std::string& _msg) {
//DbgPrint("send msg:%s\n", _msg.c_str());
m_server.send(_hdl, _msg, websocketpp::frame::opcode::text);
}
void broadcast_server::handleMsg(const connection_hdl& _hdl, const std::string& _msg) {
std::string msg = decodeURIComponent(_msg);
if (msg.empty()) {
DbgPrint("empty msg\n");
return;
}
if (msg.length() < 4) {
DbgPrint("msg length < 16\n");
return;
}
printf("recv msg:%s\n", msg.c_str());//浏览器
PackSendMsg(_hdl, msg);//回声服务
}
bool broadcast_server::getFiles(const std::string& directory, const std::string& _extension, std::vector<std::string>& _list) {
DIR* dir;
struct dirent* ent;
if ((dir = opendir(directory.c_str())) != nullptr) {
// 遍历目录
while ((ent = readdir(dir)) != nullptr) {
// 检查是否是文件并且以.php结尾
if (ent->d_type == DT_REG) { // 确保是常规文件
std::string fileName = ent->d_name;
if (fileName.size() > 4 && fileName.substr(fileName.size() - 4) == _extension) {
_list.push_back(fileName);
}
}
}
closedir(dir);
}
else {
std::cerr << "无法打开目录: " << strerror(errno) << std::endl;
return false;
}
return true;
}
//测试调用
int main() {
broadcast_server server;
server.run(9999);
}
//测试代码html/js
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>WebSocket通讯测试</title>
</head>
<body>
<h1>WebSocket连接和消息发送示例</h1>
<input type="text" id="messageInput" placeholder="输入要发送的消息">
<button onclick="sendMessage()">发送消息</button>
<div id="messageDisplay"></div>
<script>
// 创建WebSocket对象,连接到服务器,这里的地址需要替换成实际的WebSocket服务器地址
const socket = new WebSocket('ws://192.168.1.8:9999');
// 当连接成功时触发的事件
socket.onopen = function (event) {
console.log('WebSocket连接已建立');
document.getElementById('messageDisplay').innerHTML += 'WebSocket连接已建立<br>';
};
// 当收到服务器消息时触发的事件
socket.onmessage = function (event) {
var msg = event.data;
console.log('收到服务器消息: ', decodeURIComponent(msg));
document.getElementById('messageDisplay').innerHTML += '收到服务器消息: ' + event.data + '<br>';
};
// 当连接关闭时触发的事件
socket.onclose = function (event) {
console.log('WebSocket连接已关闭');
document.getElementById('messageDisplay').innerHTML += 'WebSocket连接已关闭<br>';
};
// 发送消息的函数
function sendMessage() {
const messageInput = document.getElementById('messageInput');
const message = messageInput.value;
if (message) {
var msg = encodeURIComponent(message);//%E5%93%88%E5%93%88%E5%93%88%E5%93%88%E5%93%88
socket.send(msg);
console.log('已发送消息: ', msg);
document.getElementById('messageDisplay').innerHTML += '已发送消息: ' + msg + '<br>';
}
}
</script>
</body>
</html>
//回声服务测试
//服务器测试结果图像:
//浏览器测试结果图像:
//注释信息参考:
注释:
g++ - std = c++11 linux_ws_server.cpp - o linux_ws_server.out - lboost_system - lboost_thread - lssl - lcrypto - lz
//依赖,重点静态依赖stdc++
sudo yum install libstdc++.so.6
sudo yum install glibc-static
sudo yum install libstdc++-static
sudo yum install boost-devel --nogpgcheck
sudo yum install zlib-devel
sudo yum install openssl-devel
sudo yum install sqlite sqlite-devel
//随手防火墙相关
//安装
yum install firewalld
//放行
sudo firewall - cmd --zone = public --add - port = 9999 / tcp --permanent
//重加载
sudo firewall - cmd --reload
//启动
sudo systemctl start firewalld
//停止
sudo systemctl status firewalld
*转载请注明出处:原文链接:https://cpp.vin/page/123.html