You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

前端连接C++ WebSocket服务器时出现SSL错误求助

WebSocket服务器SSL连接错误修复方案

错误原因解析

00B6571701000000:error:0A00009C:SSL routines:ssl3_get_record:http request 这个错误表示SSL层接收到了纯HTTP请求,而非TLS握手数据包。核心问题集中在三点:

  • 前端连接协议与服务器加密配置不匹配
  • 数据收发绕过了SSL加密层
  • 未实现WebSocket必须的HTTP升级握手流程

分步修复方案

1. 修正前端连接地址

服务器配置了TLS加密,前端必须使用wss://协议连接,而非ws://。示例:

const ws = new WebSocket('wss://localhost:你的端口号');

2. 替换为SSL专用收发函数

当前代码直接调用::send和recv操作原始socket,完全绕过了SSL加密层,必须替换为OpenSSL提供的SSL_write和SSL_read:

void WebSocketTCPServer::send(Connection *connection, const std::string& message) {
    SSL_write(connection->ssl, message.c_str(), message.length());
}

std::string WebSocketTCPServer::receive(Connection *connection) {
    char buffer[1024] = {0};
    int valread = SSL_read(connection->ssl, buffer, 1024);
    return {buffer, static_cast<size_t>(valread)};
}

3. 实现WebSocket HTTP升级握手

WebSocket连接建立前必须完成HTTP Upgrade握手,处理步骤如下:

#include <openssl/sha.h>
// 需自行实现Base64编码,可借助OpenSSL的EVP_EncodeBlock函数
std::string base64_encode(const unsigned char* data, size_t len) {
    BIO *bio, *b64;
    BUF_MEM *bufferPtr;

    b64 = BIO_new(BIO_f_base64());
    bio = BIO_new(BIO_s_mem());
    bio = BIO_push(b64, bio);

    BIO_write(bio, data, len);
    BIO_flush(bio);
    BIO_get_mem_ptr(bio, &bufferPtr);
    BIO_set_close(bio, BIO_NOCLOSE);
    std::string result(bufferPtr->data, bufferPtr->length - 1); // 去掉末尾换行
    BIO_free_all(bio);

    return result;
}

void WebSocketTCPServer::handleConnection(Connection *connection) {
    // 读取客户端HTTP升级请求
    std::string req = receive(connection);
    
    // 提取Sec-WebSocket-Key(简化实现,实际需完整解析HTTP头)
    size_t keyPos = req.find("Sec-WebSocket-Key: ");
    if (keyPos == std::string::npos) {
        closeConnection(connection);
        return;
    }
    std::string key = req.substr(keyPos + 19, 24);
    
    // 计算响应密钥(结合WebSocket标准magic字符串)
    std::string magic = key + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
    unsigned char sha1Result[20];
    SHA1(reinterpret_cast<const unsigned char*>(magic.c_str()), magic.length(), sha1Result);
    std::string acceptKey = base64_encode(sha1Result, 20);
    
    // 返回升级响应
    std::string resp = "HTTP/1.1 101 Switching Protocols\r\n";
    resp += "Upgrade: websocket\r\n";
    resp += "Connection: Upgrade\r\n";
    resp += "Sec-WebSocket-Accept: " + acceptKey + "\r\n\r\n";
    send(connection, resp);
    
    // 握手完成后,才能处理WebSocket帧数据
    std::string msg = receive(connection);
    printf("%s", msg.c_str());
}

4. 适配OpenSSL 3.x初始化API

你当前使用的SSL_library_init()等是旧版API,OpenSSL 3.x推荐使用新初始化方式:

void WebSocketTCPServer::startServer(int port) {
    // 替换旧初始化代码
    OPENSSL_init_ssl(OPENSSL_INIT_LOAD_SSL_STRINGS, NULL);
    OPENSSL_init_crypto(OPENSSL_INIT_LOAD_CRYPTO_STRINGS, NULL);

    const SSL_METHOD* method = TLS_server_method(); // 自动适配最新TLS版本
    // 后续证书加载、socket创建逻辑保持不变...
}

额外注意事项

  • 确保cert.pem和key.pem文件路径正确,且进程有读取权限
  • 测试时需处理浏览器对自签名证书的安全提示(或手动添加信任)
  • 多线程场景下需初始化OpenSSL线程锁,避免并发问题

内容的提问来源于stack exchange,提问作者Pixel Coin

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.10 22:20:46