L o a d i n g . . .
主打一个C++
文章详情

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>

//回声服务测试

//服务器测试结果图像:

image.png

//浏览器测试结果图像:

image.png

//注释信息参考:

注释:

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

作者近期文章
  • 随手笔记
  • 主打一个C++   2025-01-11 20:02:01
  • 都2000000025年了。还有不能随意访问guthub的,仔细看。在国内其实是可以正常访问的,gfw并没屏蔽。这里给出其中一个简单直接的方法稳定访问。1. 随便百度一个”dn
提示
×
确定
数据库执行: 8次 总耗时: 0.01s
页面加载耗时: 



wechat +447752296473
wechat cpp-blog