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

WebSocket服务器仅向wscat回显消息,无法推送至JavaScript客户端

问题解决:WebSocket服务器实现消息广播到所有客户端

你的核心问题是当前服务器仅将消息回传给发送消息的客户端(wscat),没有维护在线客户端的连接列表,无法实现消息广播到其他客户端(比如浏览器中的JS客户端)。以下是修改方案:

修改后的server.c代码

#include <libwebsockets.h>
#include <string.h>
#include <stdio.h>
#include <pthread.h>

// 全局连接链表,存储所有活跃的WebSocket连接
struct client_node {
    struct lws *wsi;
    struct client_node *next;
};
static struct client_node *client_list = NULL;
static pthread_mutex_t client_list_mutex = PTHREAD_MUTEX_INITIALIZER;

// 将新连接加入链表
static void add_client(struct lws *wsi) {
    pthread_mutex_lock(&client_list_mutex);
    struct client_node *new_node = malloc(sizeof(struct client_node));
    if (new_node) {
        new_node->wsi = wsi;
        new_node->next = client_list;
        client_list = new_node;
        printf("Client added, total connections: %d\n", lws_get_count_wsi(wsi->context));
    }
    pthread_mutex_unlock(&client_list_mutex);
}

// 从链表移除断开的连接
static void remove_client(struct lws *wsi) {
    pthread_mutex_lock(&client_list_mutex);
    struct client_node **curr = &client_list;
    while (*curr) {
        if ((*curr)->wsi == wsi) {
            struct client_node *temp = *curr;
            *curr = (*curr)->next;
            free(temp);
            printf("Client removed, total connections: %d\n", lws_get_count_wsi(wsi->context));
            break;
        }
        curr = &(*curr)->next;
    }
    pthread_mutex_unlock(&client_list_mutex);
}

// 向所有除发送方外的客户端广播消息
static void broadcast_message(struct lws *exclude_wsi, const unsigned char *msg, size_t len) {
    pthread_mutex_lock(&client_list_mutex);
    struct client_node *curr = client_list;
    while (curr) {
        if (curr->wsi != exclude_wsi && lws_is_valid_wsi(curr->wsi)) {
            unsigned char buffer[LWS_SEND_BUFFER_PRE_PADDING + len + LWS_SEND_BUFFER_POST_PADDING];
            memcpy(&buffer[LWS_SEND_BUFFER_PRE_PADDING], msg, len);
            lws_write(curr->wsi, &buffer[LWS_SEND_BUFFER_PRE_PADDING], len, LWS_WRITE_TEXT);
        }
        curr = curr->next;
    }
    pthread_mutex_unlock(&client_list_mutex);
}

static int callback_ws(struct lws *wsi, enum lws_callback_reasons reason,
                       void *user, void *in, size_t len) {
    switch (reason) {
        case LWS_CALLBACK_ESTABLISHED:
            printf("Connection established\n");
            add_client(wsi);
            break;
        case LWS_CALLBACK_CLOSED:
            printf("Connection closed\n");
            remove_client(wsi);
            break;
        case LWS_CALLBACK_RECEIVE:
            printf("Received message length: %d\n", (int)len);
            char buffer[1024];
            if (len < sizeof(buffer) - 1) {
                memcpy(buffer, in, len);
                buffer[len] = '\0';
                printf("Message received: %s\n", buffer);
                
                // 广播消息到所有其他客户端
                broadcast_message(wsi, (unsigned char*)buffer, len);
                
                // 可选:保留回显给发送方的逻辑
                // unsigned char echo_msg[LWS_SEND_BUFFER_PRE_PADDING + len + LWS_SEND_BUFFER_POST_PADDING];
                // memcpy(&echo_msg[LWS_SEND_BUFFER_PRE_PADDING], buffer, len);
                // lws_write(wsi, &echo_msg[LWS_SEND_BUFFER_PRE_PADDING], len, LWS_WRITE_TEXT);
            }
            break;
        default:
            break;
    }
    return 0;
}

static struct lws_protocols protocols[] = {
    { "ws", callback_ws, 0, 1024 },
    { NULL, NULL, 0, 0 } // Terminator
};

int main(void) {
    struct lws_context_creation_info info;
    memset(&info, 0, sizeof info);
    info.port = 8080;
    info.protocols = protocols;
    struct lws_context *context = lws_create_context(&info);

    if (context == NULL) {
        fprintf(stderr, "lws init failed\n");
        return -1;
    }

    printf("Starting server on port 8080...\n");
    while (1) {
        lws_service(context, 1000);
    }

    lws_context_destroy(context);
    return 0;
}

关键改动说明

  1. 维护客户端连接列表:用链表存储所有活跃的struct lws*连接实例,配合互斥锁保证线程安全(即使libwebsockets使用多线程服务,也能避免并发访问问题)。
  2. 连接生命周期管理:
    • LWS_CALLBACK_ESTABLISHED:新客户端连接时,将其加入链表。
    • LWS_CALLBACK_CLOSED:客户端断开连接时,从链表中移除。
  3. 消息广播逻辑:收到消息后,遍历连接列表,将消息发送给所有非发送方的客户端,实现wscat发送的命令同步到浏览器JS客户端。

验证步骤

  1. 重新编译服务器:gcc server.c -o server -lwebsockets -lpthread
  2. 启动服务器:./server
  3. 打开浏览器访问index.html,确认控制台显示连接成功。
  4. 用wscat连接服务器:wscat -c ws://localhost:8080
  5. 在wscat中发送颜色命令(比如red或#ff0000),检查浏览器中的SVG圆形颜色是否同步变化。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.22 12:15:16