libwebsocket建立服务器需要编写LWS_CALLBACK_ADD_HEADERS事件处理

最近在使用libwebsocket,感觉它搭建Http与websocket服务器比较简单,不像poco库那么庞大,但当我使用它建立websocket服务器后,发现websocket客户端连接一直没有连接成功,不知道什么原因,经过一天的调试,终于搞通,因此记录一下被坑的一天,以下是调通的完整DEMO:

复制代码
#include <libwebsockets.h>
#include <stdio.h>
#include <string.h>

/* 定义支持的协议 */
enum protocols {
    PROTOCOL_HTTP = 0,
    PROTOCOL_CHAT,
    PROTOCOL_JSON,
    PROTOCOL_COUNT
};

/* WebSocket 协议回调函数 */
static int callback_chat(struct lws* wsi, enum lws_callback_reasons reason, void* user, void* in, size_t len) {
    printf("callback_chat %d\n", reason);
    switch (reason) {
    case LWS_CALLBACK_ESTABLISHED:
        printf("[Chat] 客户端连接成功 (协议: %s)\n", lws_get_protocol(wsi)->name);
        break;
    case LWS_CALLBACK_RECEIVE:
        printf("[Chat] 收到消息: %.*s\n", (int)len, (char*)in);
        // 回声
        lws_write(wsi, (unsigned char*) in, len, LWS_WRITE_TEXT);
        break;
    default:
        break;
    }
    return 0;
}

static int callback_json(struct lws* wsi, enum lws_callback_reasons reason, void* user, void* in, size_t len) {
    printf("callback_json %d\n", reason);
    switch (reason) {
    case LWS_CALLBACK_ESTABLISHED:
        printf("[JSON] 客户端连接成功 (协议: %s)\n", lws_get_protocol(wsi)->name);
        break;
    case LWS_CALLBACK_RECEIVE:
        printf("[JSON] 收到消息: %.*s\n", (int)len, (char*)in);
        // 返回 JSON 响应
        const char* response = "{\"status\":\"ok\",\"data\":\"received\"}";
        lws_write(wsi, (unsigned char*)response, strlen(response), LWS_WRITE_TEXT);
        break;
    }
    return 0;
}

/* HTTP 回调函数(处理非 WebSocket 请求) */
static int callback_http(struct lws* wsi, enum lws_callback_reasons reason, void* user, void* in, size_t len) {
    printf("callback_http %d\n", reason);
    switch (reason) {
    case LWS_CALLBACK_HTTP: {
        printf("收到 HTTP 请求: %s\n", (char*)in);
    }
    case LWS_CALLBACK_ESTABLISHED:
        printf("收到 websocket连接成功\n");
        lws_callback_on_writable(wsi);
        break;
    case LWS_CALLBACK_SERVER_WRITEABLE:
        printf("收到 LWS_CALLBACK_SERVER_WRITEABLE len:%u user:%d in:%d\n", len, user, in);
        if (len > 0)
        {
            printf("收到 LWS_CALLBACK_SERVER_WRITEABLE data:%s\n", (char*)in);
            lws_write(wsi, (unsigned char*)in, len, LWS_WRITE_TEXT);
        }
        break;
    case LWS_CALLBACK_ADD_HEADERS: {
        struct lws_process_html_args* args =
            (struct lws_process_html_args*)in;
        printf("收到 LWS_CALLBACK_ADD_HEADERS data:%s\n", (char*)&args->p);
        if (lws_add_http_header_by_name(wsi,
            NULL,NULL, 0,
            (unsigned char**)&args->p,
            (unsigned char*)args->p + args->max_len))//必须要调用此函数后libwebsocket才会发出数据,也就是说如果要发送HTTP 101状态数据时,要调用这个才会发出
            return 1;

        break;
    }

    default:
        break;
    }
    return 0;
}

static int callback_text(struct lws* wsi, enum lws_callback_reasons reason, void* user, void* in, size_t len) {
    printf("callback_text %d\n", reason);
    //switch (reason) {
    //default:
    //    break;
    //}
    return 0;
}
static int callback_websocket(struct lws* wsi, enum lws_callback_reasons reason, void* user, void* in, size_t len) {
    printf("callback_websocket %d\n", reason);
    //switch (reason) {
    //default:
    //    break;
    //}
    return 0;
}

/* 协议列表 */
static struct lws_protocols protocols[] = {
    /* 第一个协议必须用于 HTTP */
    {
        "http",
        callback_http,
        0,
        0
    },
    /* WebSocket 协议 */
    {
        "chat",
        callback_chat,
        0,
        1024
    },
    {
        "json",
        callback_json,
        0,
        1024
    },
    {
        "text",
        callback_text,
        0,
        1024
    },
    {
        "websocket",
        callback_websocket,
        0,
        1024
    },
    { NULL, NULL, 0, 0 } // 结束标记
};

int main() {
    struct lws_context_creation_info info;
    memset(&info, 0, sizeof(info));

    /* 基本配置 */
    info.port = 9002;                           // 监听端口
    info.protocols = protocols;                 // 协议列表
    info.gid = -1;
    info.uid = -1;
    info.options = LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT; // 启用 SSL(可选)
    info.options |= LWS_SERVER_OPTION_ALLOW_NON_SSL_ON_SSL_PORT;
    //info.options |= LWS_SERVER_OPTION_LOG_ALL;

    /* 创建上下文 */
    struct lws_context* context = lws_create_context(&info);
    if (!context) {
        fprintf(stderr, "libwebsockets 初始化失败\n");
        return -1;
    }

    printf("服务器启动,监听端口 9002...\n");
    printf("测试命令:\n");
    printf("  - WebSocket (Chat): wscat -c ws://localhost:9002 -p chat\n");
    printf("  - WebSocket (JSON): wscat -c ws://localhost:9002 -p json\n");
    printf("  - HTTP: curl http://localhost:9002\n");

    /* 事件循环 */
    while (1) {
        lws_service(context, 0);
    }

    lws_context_destroy(context);
    return 0;
}

需要值得注意的是,必须要写LWS_CALLBACK_ADD_HEADERS事件的代码,libwesocket才会发送"HTTP/1.1 101 Switching Protocols\r\n"协议,让客户端连接成功,否则客户端认为一直不能连接成功。

相关推荐
阿巴~阿巴~1 小时前
CPU 指令集、权限与用户态内核态机制
linux·运维·服务器·指令集·权限·用户态内核态
航Hang*1 小时前
第1章:初识Linux系统——第8节:查看/修改权限控制和ACL
linux·运维·服务器·笔记·操作系统
一个处女座的程序猿O(∩_∩)O2 小时前
深入浅出 SSE:实现服务器向客户端的单向实时通信
运维·服务器
捷智算云服务2 小时前
DGX A100服务器常见故障解析与维修攻略
运维·服务器
安当加密2 小时前
基于TDE透明加密实现异地服务器间文件自动加密传输的实践与思考
运维·服务器
北塔软件2 小时前
各品牌服务器IPMI配置实战经验分享
服务器·git·github
我爱钱因此会努力2 小时前
初始化服务器
linux·运维·服务器·tcp/ip·centos
祈祷苍天赐我java之术2 小时前
什么是Nginx?:掌握高性能 Web 服务器核心技术
服务器·前端·nginx
曦月合一2 小时前
解决由于没有远程桌面授权服务器可以提供许可证,远程会话被中断.的方法
运维·服务器·window server
angushine2 小时前
Shell脚本判断服务器SSH免密是否配置完成
运维·服务器·ssh