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"协议,让客户端连接成功,否则客户端认为一直不能连接成功。

相关推荐
邪恶的贝利亚2 小时前
FFmpeg 硬核指南:从底层架构到播放器全链路开发实战 基础
linux·服务器·ffmpeg
黑金IT4 小时前
如何在 Electron 应用中安全地进行主进程与渲染器进程通信
服务器·安全·electron
绵绵细雨中的乡音7 小时前
Linux-进度条小程序
linux·运维·服务器
_丿丨丨_8 小时前
Linux下 文件的查找、复制、移动和解压缩
linux·运维·服务器
DanmF--8 小时前
详解与HTTP服务器相关操作
服务器·网络·网络协议·http·unity·c#
mit6.8248 小时前
Linux 系统盘制作 | 引导加载器(GRUB 为例)| mount
linux·运维·服务器
开开心心就好9 小时前
免费多平台运行器,手机畅玩经典主机大作
服务器·python·学习·安全·微信·智能手机·ocr
沐风_ZTL9 小时前
ZLMediaKit流媒体服务器
运维·服务器·音视频·rk3588·c/c++·流媒体服务器
会敲代码的Steve9 小时前
Rsync+sersync2实现目录实时同步
服务器·网络