forust 2025-03-27 16:08 采纳率: 33.3%
浏览 6
已结题

uwebsockets连接直接退出,不输出如何内容

代码如下,因为是初次尝试,所以比较简单。我自己用python写的服务端,使用python是可以连接的。会输出下面这行东西:

_PROCESS_REQUEST: Request(path='/', headers=Headers([('Host', 'localhost:8765'), ('Upgrade', 'websocket'), ('Connection', 'Upgrade'), ('Sec-WebSocket-Key', '0itrtPOKGWQ1euqU2wwd6Q=='), ('Sec-WebSocket-Version', '13'), ('Sec-WebSocket-Extensions', 'permessage-deflate; client_max_window_bits'), ('User-Agent', 'Python/3.11 websockets/14.1')]), exception=None)
Received: {"method": "SUBSCRIBE", "params": [], "id": 1}

但是如果使用下面的C++代码就会直接退出,除了下面这行没有其余如何输出

Debug\ws_0.exe (进程 36732)已退出,代码为 0 (0x0)。

请各大伙帮我看一下问题在哪里,谢谢!


#define _CRT_SECURE_NO_WARNINGS // 禁用不安全警告

#include <iostream>
#include "uwebsockets/App.h"

int main() {
    /* ws->getUserData returns one of these */
    struct PerSocketData {
        uWS::CompressOptions compression = uWS::DISABLED;
        unsigned int maxPayloadLength = 16 * 1024;
        unsigned short idleTimeout = 120;
        unsigned int maxBackpressure = 64 * 1024;
        bool closeOnBackpressureLimit = false;
        bool resetIdleTimeoutOnSend = false;
        bool sendPingsAutomatically = true;
        unsigned short maxLifetime = 0;
    };
    uWS::App().ws<PerSocketData>("/*", {
        .upgrade = [&](auto* res, auto* req, auto* context) {
            // 从请求中提取必要的 WebSocket 握手头部字段
            std::string_view url = req->getUrl();
            std::string_view secWebSocketKey = req->getHeader("sec-websocket-key");
            std::string_view secWebSocketProtocol = req->getHeader("sec-websocket-protocol");
            std::string_view secWebSocketExtensions = req->getHeader("sec-websocket-extensions");

            std::cout << "Upgrade requested for URL: " << url << std::endl;
            std::cout << "sec-websocket-key: " << secWebSocketKey << std::endl;
            std::cout << "sec-websocket-protocol: " << secWebSocketProtocol << std::endl;
            std::cout << "sec-websocket-extensions: " << secWebSocketExtensions << std::endl;

            // 你可以在这里进行一些校验,例如检查 origin 或 token
            // 如果需要拒绝升级,可以调用 res->end("拒绝升级");

            // 调用 upgrade() 完成升级,并为该连接分配一个新的 PerSocketData 对象
            res->upgrade(
                new PerSocketData(),      // 指向用户数据的指针,连接关闭时会被释放
                secWebSocketKey,          // WebSocket 握手关键头部
                secWebSocketProtocol,     // 协议
                secWebSocketExtensions,   // 扩展
                context                   // HTTP 上下文(内部使用,不用更改)
            );
        },

        .open = [](auto* ws) {
            std::cout << "WebSocket connected!" << std::endl;
            // 发送一条测试消息
            ws->send("Hello, server!");
        },
        .message = [](auto* ws, std::string_view message, uWS::OpCode opCode) {
            std::cout << "Received message from server: " << message << std::endl;
        },
        .close = [](auto* ws, int code, std::string_view message) {
            std::cout << "Connection closed with code " << code << " and message: " << message << std::endl;
        }
        }).connect("ws://localhost:8765", nullptr)  // 假设的 WebSocket 地址
        .run();

    return 0;
}

python 服务端的代码


import asyncio
import websockets
from datetime import datetime

# Set of connected clients
connected_clients = set()

async def handler(websocket):
    # Add the client to the connected clients set
    connected_clients.add(websocket)    
    try:
        # Keep listening for incoming messages from the client
        async for message in websocket:
            # Broadcast the message to all connected clients
            print('Received: ', message)
            await broadcast(message)
    except Exception as e:
        print('handler出现错误: %s' % e)
    finally:
        connected_clients.remove(websocket) 

async def process_request(connection, req):
    print('PROCESS_REQUEST:', req)
    
async def process_response(connection, req, res):
    print('PROCESS_RESPONSE:', req, res)

async def broadcast(message):
    # Broadcast the message to all connected clients
    try:
        for client in connected_clients:
            await client.send(message)
    except Exception as e:
        print('broadcast出现错误: %s' % e)


async def main():
    async with websockets.serve(handler, "localhost", 8765, 
                                process_request=process_request, 
                                process_response=None):
        await asyncio.Future()  # run forever
        loop = asyncio.get_running_loop() #获取当前event_loop对象
        loop.create_task(broadcast())     # 添加新的异步广播任务


if __name__ == "__main__":
    asyncio.run(main())


  • 写回答

3条回答 默认 最新

  • 宝码香车 优质创作者: JavaScript技术领域 2025-03-27 17:06
    关注

    让【宝码香车】来帮你解答,本回答参考DeepSeek编写,并整理提供。
    如果还有疑问可以点击头像关注私信或评论。如果答案让您满意,请采纳、点赞、关注,非常感谢!

    根据你提供的代码和问题描述,C++客户端直接退出的原因主要是没有正确处理事件循环和连接超时问题。以下是修改后的解决方案:
    
    #define _CRT_SECURE_NO_WARNINGS
    #include <iostream>
    #include <thread>
    #include "uwebsockets/App.h"
    
    int main() {
        struct PerSocketData {
            // 保持原有结构
        };
    
        bool connected = false;
        bool closed = false;
    
        uWS::App().ws<PerSocketData>("/*", {
            .upgrade = [](auto* res, auto* req, auto* context) {
                std::cout << "Upgrade requested" << std::endl;
                res->upgrade<PerSocketData>(
                    {},
                    req->getHeader("sec-websocket-key"),
                    req->getHeader("sec-websocket-protocol"),
                    req->getHeader("sec-websocket-extensions"),
                    context
                );
            },
            .open = [&](auto* ws) {
                std::cout << "WebSocket connected!" << std::endl;
                connected = true;
                ws->send("Hello from C++ client!");
            },
            .message = [](auto* ws, std::string_view message, uWS::OpCode opCode) {
                std::cout << "Received: " << message << std::endl;
            },
            .close = [&](auto* ws, int code, std::string_view message) {
                std::cout << "Connection closed" << std::endl;
                closed = true;
            }
        }).connect("ws://localhost:8765", [](auto* token) {
            if (!token) {
                std::cerr << "Connection failed!" << std::endl;
                exit(1);
            }
            std::cout << "Connecting..." << std::endl;
        }).run();
    
        // 添加简单的事件循环防止立即退出
        while (!connected && !closed) {
            std::this_thread::sleep_for(std::chrono::milliseconds(100));
        }
    
        // 保持连接一段时间
        std::this_thread::sleep_for(std::chrono::seconds(5));
    
        return 0;
    }
    

    主要修改点:

    1. 添加了连接状态跟踪变量 connectedclosed
    2. connect 方法中添加了回调函数处理连接失败情况
    3. 添加了简单的事件循环防止程序立即退出
    4. 增加了连接保持时间

    如果问题仍然存在,建议检查以下几点:

    1. 确保 uWebSockets 库正确安装并链接
    2. 检查防火墙设置是否阻止了连接
    3. 尝试在 connect 回调中添加错误处理
    4. 可以添加超时机制,比如:
    
    // 添加连接超时检测
    auto start = std::chrono::steady_clock::now();
    while (!connected && !closed) {
        auto now = std::chrono::steady_clock::now();
        if (now - start > std::chrono::seconds(5)) {
            std::cerr << "Connection timeout!" << std::endl;
            break;
        }
        std::this_thread::sleep_for(std::chrono::milliseconds(100));
    }
    

    如果还是无法连接,建议使用 Wireshark 等工具抓包分析网络通信情况。

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(2条)

报告相同问题?

问题事件

  • 系统已结题 4月5日
  • 已采纳回答 3月28日
  • 修改了问题 3月27日
  • 创建了问题 3月27日